题意
三维空间的n个点 p [ 1 ] , p [ 2 ] , . . . p [ n ] p[1],p[2],...p[n] p[1],p[2],...p[n],给定区域 1 < = x < = p , 1 < = y < = q , 1 < = z < = r 1<=x<=p, 1<=y<=q, 1<=z<=r 1<=x<=p,1<=y<=q,1<=z<=r,问在区域内有多少个点 ( x , y , z ) (x,y,z) (x,y,z)满足对于n个点中任意一个点p[i],至少都有两个维度的坐标比p[i]大。
思路
正着求不是很好算,就求不能被有多少个
(
x
,
y
,
z
)
(x,y,z)
(x,y,z)满足n个点中至少存在一点p[i],使得p[i]至少有两个维度的坐标小于等于点
(
x
,
y
,
z
)
(x,y,z)
(x,y,z)。那么可以枚举一个维度去计算平面上的满足情况。
将n个点按z排序,枚举z从1到r,假设当z = c时候,
p
[
1
]
,
p
[
2
]
.
.
p
[
k
]
p[1],p[2]..p[k]
p[1],p[2]..p[k]的z坐标都小于c,
p
[
k
+
1
]
,
.
.
.
p
[
n
]
p[k + 1],...p[n]
p[k+1],...p[n]z坐标大于等于c,
p
x
=
m
a
x
(
p
[
k
+
1
]
.
x
,
p
[
k
+
2
]
.
x
.
.
.
.
p
[
n
]
.
x
)
,
p
y
=
m
a
x
(
p
[
k
+
1
]
.
y
,
p
[
k
+
2
]
.
y
,
.
.
.
p
[
n
]
.
y
)
px = max(p[k + 1].x,p[k + 2].x....p[n].x),py = max(p[k + 1].y,p[k + 2].y,...p[n].y)
px=max(p[k+1].x,p[k+2].x....p[n].x),py=max(p[k+1].y,p[k+2].y,...p[n].y),那么对于后半部分
[
k
+
1
,
n
]
[k+1,n]
[k+1,n]合法区域为整个平面区域扣掉以
(
p
x
+
1
,
p
y
+
1
)
为
左
下
角
,
(
p
,
q
)
(px + 1,py + 1)为左下角,(p,q)
(px+1,py+1)为左下角,(p,q)为右上角的矩形。对于前半部分
[
1
,
k
]
[1,k]
[1,k],对应k个矩形
(
0
,
0
)
为
左
下
角
,
(
p
[
i
]
.
x
,
p
[
i
]
.
y
)
为
右
上
角
(0,0)为左下角,(p[i].x,p[i].y)为右上角
(0,0)为左下角,(p[i].x,p[i].y)为右上角,前半部分的合法区域就是这k个矩形的并,前半部分的区域再并上后半部分区域,就是当z = c时,不合法的情况。假设当z = r时候,所有矩形都在前半部分,后半部分为空,那么此时的区域面积大小可以用单调栈直接处理。当z往下递减的时候,相当于前半部分要去掉一个矩形,后半部分的区域用这个矩形更新一下,后半部分的区域实际上是一个不断扩大的区域,并且一定包含新加入的这个矩形,那么可以发现z = c的时候的所有情况一定都包含在 z = c-1的情况中,那么每次前半部分的区域实际上可以看成不变的就是n个矩形的并,直接提前预处理出来,然后每次并上后半部分的区域,而后半部分的区域是一个比较规整的区域(一个大矩形,挖掉右上角的一个矩形),对单调栈处理后的n个矩形并的区域,前后扣一扣就可以算出并集。从大到小枚举完z就可以计算出所有不合法的,全部扣掉不合法的就算完答案了。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,int>pii;
typedef vector<int>vi;
#define rep(i,a,b) for(int i=(a);i<(b);i++)
#define fi first
#define se second
#define de(x) cout<<#x<<"="<<x<<"\n"
#define dd(x) cout<<#x<<"="<<x<<" "
#define pb(x) push_back(x)
#define all(x) x.begin(),x.end()
#define sz(x) (int)x.size()
#define lowbit(a) ((a)&-(a))
#define per(i,a,b) for(int i=(b)-1;i>=(a);--i)
const int N=5e5+5;
const ll mod = 1e9 + 7;
int n , p , q , h;
struct node{
int x,y,z,id;
}a[N],b[N];
bool cmp1(node a,node b){
if(a.x != b.x)return a.x < b.x;
return a.y < b.y;
}
bool cmp2(node a,node b){
return a.z > b.z;
}
ll calc(ll x,ll y){
return (ll)p*q - (p-x)*(q-y);
}
int st[N];
ll sum[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>p>>q>>h;
rep( i , 1 , n + 1)
cin>>a[i].x>>a[i].y>>a[i].z;
sort(a + 1,a + n + 1,cmp1);
int top = 0;
rep( i , 1 , n + 1){
while(top && a[st[top]].y <= a[i].y)top--;
st[++top] = i;
}
ll un = 0,ans = 0;
rep( i ,1 , top + 1){
b[i] = a[st[i]];
}
rep( i , 1 , top + 1){
un += (ll)(a[st[i]].x - a[st[i - 1]].x)*a[st[i]].y;
sum[i] = un;
}
sort(a + 1,a + n + 1,cmp2);
int px =0,py = 0;
int j = 1;
int l = 1,r = top;
for(int i = h;i >= 1;--i){
while(j<=n && a[j].z >= i){
px = max(px,a[j].x);
py = max(py,a[j].y);
j++;
}
while(l <= top && b[l].x <= px)l++;
while(r >= 1 && b[r].y <= py)r--;
if(px == 0 && py == 0)
ans += un;
else{
ll res = 0;
if(l<=r){
res = (sum[r] - sum[l - 1])-((ll)py*(b[r].x - px) + (ll)b[l].y*(px - b[l - 1].x));
}
ans += calc(px,py) + res;
}
}
ans = (ll)p*q*h - ans;
cout<<ans<<endl;
return 0;
}