HDU 5126 stars 4维偏序, CDQ套CDQ
题意:在一个星空中,按着时间会出现一些点,现在john想知道,在某个时间内有多少个星星是的坐标是满足条件的。(x1<=x<=x2, y1 <= y <= y2, z1 <= z <= z2).
题解:先简化问题,如果我们就统计出现所有 x <= x2 , y <= y2, z <= z2的点的话,这就是一个4维偏序题。
对于这个统计点数来说, 我们先按照题目给定点的顺序来进行CDQ, 这样在CDQ内只有左边的添加点会对右边的询问点产生影响,然后我们再把这些会对答案找出影响的点拿出来,
对这些点进行关于X轴内一个sort,对于sort完的结果,我们再进行cdq, 这样在cdq内还是只有左边的左边的添加点会对右边的询问点产生影响,然后我们再把这些会对答案找出影响的点拿出来。
这样就变成了2维偏序题了, 再对y sort, 然后for一遍询问答案把答案加进去就好了。
现在的问题就变成了怎么询问这个长方体内点的个数。 我们可以用差分的思想去维护这个矩形。
我们对一次询问可以拆成8次询问。
Q1( X1-1, Y1-1, Z2) Q2 (X1-1, Y2, Z2) Q3 (X2, Y1-1, Z2) Q4(X2,Y2,Z2)
Q5( X1-1, Y1-1, Z1-1) Q6 (X1-1, Y2, Z1-1) Q7 (X2, Y1-1, Z1-1) Q8(X2,Y2,Z1-1)
可以发现 Q1-Q2-Q3+Q4 得到的是 z <= z2 x1<=x <= x2 && y1 <= y <= y2 的点的个数和。
现在我们在减去 z <= z1-1 x1<=x <= x2 && y1 <= y <= y2 的个数和就是答案了。
在CDQ的过程中, 我们可以加上一个剪枝 即对于这个CDQ来说,如果左边没有添加点 或者 右边没有询问点 就再进行处理了, 因为不会对答案造成影响。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); 4 #define LL long long 5 #define ULL unsigned LL 6 #define fi first 7 #define se second 8 #define pb push_back 9 #define lson l,m,rt<<1 10 #define rson m+1,r,rt<<1|1 11 #define lch(x) tr[x].son[0] 12 #define rch(x) tr[x].son[1] 13 #define max3(a,b,c) max(a,max(b,c)) 14 #define min3(a,b,c) min(a,min(b,c)) 15 typedef pair<int,int> pll; 16 const int inf = 0x3f3f3f3f; 17 const LL INF = 0x3f3f3f3f3f3f3f3f; 18 const LL mod = (int)1e9+7; 19 const int N = 1e6 + 100; 20 struct Node{ 21 int x, y, z, op, id; 22 }A[N], B[N], C[N]; 23 int ans[N]; 24 int zz[N]; 25 int tot = 0; 26 int zsz; 27 int bit[N]; 28 void add(int x, int v){ 29 while(x <= zsz){ 30 bit[x] += v; 31 x += x & (-x); 32 } 33 } 34 int query(int x){ 35 int ret = 0; 36 while(x > 0){ 37 ret += bit[x]; 38 x -= x & (-x); 39 } 40 return ret; 41 } 42 bool cmp_x(Node & n1, Node & n2){ 43 if(n1.x != n2.x) return n1.x < n2.x; 44 if(n1.y != n2.y) return n1.y < n2.y; 45 if(n1.z != n2.z) return n1.z < n2.z; 46 return n1.id < n2.id; 47 } 48 bool cmp_y(Node & n1, Node & n2){ 49 if(n1.y != n2.y) return n1.y < n2.y; 50 if(n1.z != n2.z) return n1.z < n2.z; 51 return n1.id < n2.id; 52 } 53 void cdq(int l, int r){ 54 if(l >= r) return ; 55 int m = l+r >> 1; 56 cdq(l, m); cdq(m+1, r); 57 int k = 0; 58 for(int i = l; i <= m; i++) 59 if(!B[i].id) C[++k] = B[i]; 60 for(int i = m+1; i <= r; i++) 61 if(B[i].id) C[++k] = B[i]; 62 if(C[1].id != 0 || C[k].id == 0) return ;/// 剪枝 63 sort(C+1, C+1+k, cmp_y); 64 for(int i = 1; i <= k; i++){ 65 if(C[i].op) 66 ans[C[i].id] += query(C[i].z) * C[i].op; 67 else 68 add(C[i].z, 1); 69 } 70 for(int i = 1; i <= k; i++){ 71 if(C[i].op); 72 else add(C[i].z, -1); 73 } 74 } 75 void CDQ(int l, int r){ 76 if(l == r) return ; 77 int m = l+r >> 1; 78 CDQ(l,m); CDQ(m+1,r); 79 int k = 0; 80 for(int i = l; i <= m; i++) 81 if(!A[i].id) B[++k] = A[i]; 82 for(int i = m+1; i <= r; i++) 83 if(A[i].id) B[++k] = A[i]; 84 if(B[1].id != 0 || B[k].id == 0) return ;/// 剪枝 85 sort(B+1, B+1+k, cmp_x); 86 cdq(1,k); 87 } 88 89 inline void nownode(int x, int y, int z, int op, int id){ 90 ++tot; A[tot].x = x; A[tot].y = y; zz[tot] = z; 91 A[tot].z = z; A[tot].op = op; A[tot].id = id; 92 } 93 int main(){ 94 int T; 95 scanf("%d", &T); 96 while(T--){ 97 int n, op, x1, y1, z1, x2, y2, z2, m = 0; 98 tot = 0; 99 scanf("%d", &n); 100 for(int i = 1; i <= n; i++){ 101 scanf("%d", &op); 102 if(op == 1){ 103 scanf("%d%d%d", &x1, &y1, &z1); 104 nownode(x1, y1, z1, 0, 0); 105 } 106 else { 107 m++; 108 ans[m] = 0; 109 scanf("%d%d%d", &x1, &y1, &z1); 110 scanf("%d%d%d", &x2, &y2, &z2); 111 nownode(x2,y2,z2,1,m); 112 nownode(x1-1,y1-1,z2,1,m); 113 nownode(x2,y1-1,z2,-1,m); 114 nownode(x1-1,y2,z2,-1,m); 115 116 nownode(x2,y2,z1-1,-1,m); 117 nownode(x1-1,y1-1,z1-1,-1,m); 118 nownode(x2,y1-1,z1-1,1,m); 119 nownode(x1-1,y2,z1-1,1,m); 120 } 121 } 122 sort(zz+1, zz+tot+1); 123 zsz = unique(zz+1, zz+tot+1) - zz - 1; 124 for(int i = 1; i <= tot; i++) 125 A[i].z = lower_bound(zz+1, zz+1+zsz, A[i].z) - zz; 126 CDQ(1, tot); 127 for(int i = 1; i <= m; i++) 128 printf("%d\n", ans[i]); 129 } 130 return 0; 131 }