题目大意:一共有Q(1<=Q<=50000)组操作,操作分为两种:
1.在x,y,z处添加一颗星星
2.询问以(x1,y1,z1)与(x2,y2,z2)为左上和右下顶点的矩形之间的星星数
所有坐标取值范围均为[1,1e9]
思路:由于坐标取值范围太大(即使离散化后也很大),3维的数组肯定开不下,所以只能另辟蹊径。
解法一(两重CDQ+树状数组,需将z坐标离散化):
1)将每个查询操作拆分为8个(容斥),将所有操作放入一个数组qr中
2)将所有操作按时间排序(其实不用,因为读入的顺序就是按时间排好的)
3)第一次分治:将qr中每个子区间按x坐标从小到大排序,将左区间元素与右区间查询放入qr2中
4)第二次分治(嵌套在第一次分治中):将qr2中每个子区间按y坐标从小到大排序,统计左区间元素对右区间查询的贡献(利用树状数组记录z值)
注意每次分治结束后,需将左右区间的所有元素按相应坐标大小归并排好序。另外离散化的时候注意下标要从1开始而不是从0开始,否则树状数组可能会陷入死循环(在这个地方T了n次...QAQ)
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 const int N=5e5+10; 5 struct QR { 6 int f,x,y,z,i; 7 } qr[N],qr2[N],qr3[N]; 8 int c[N],n,ans[N],nq,tot,zz[N],maxz; 9 int lowbit(int x) {return x&-x;} 10 void add(int u,int x) { 11 for(; u<=maxz; u+=lowbit(u))c[u]+=x; 12 } 13 int get(int u) { 14 int ret=0; 15 for(; u; u-=lowbit(u))ret+=c[u]; 16 return ret; 17 } 18 19 void cdq2(int l,int r) { 20 if(l==r)return; 21 int mid=(l+r)>>1; 22 cdq2(l,mid),cdq2(mid+1,r); 23 int L=l,R=mid+1; 24 for(; R<=r; ++R)if(qr2[R].f) { 25 for(; L<=mid&&qr2[L].y<=qr2[R].y; ++L)if(!qr2[L].f)add(qr2[L].z,1); 26 ans[qr2[R].i]+=get(qr2[R].z)*qr2[R].f; 27 } 28 for(int i=l; i<L; ++i)if(!qr2[i].f)add(qr2[i].z,-1); 29 L=l,R=mid+1; 30 for(int i=l; i<=r; ++i) { 31 if(R>r||(L<=mid&&qr2[L].y<=qr2[R].y))qr3[i]=qr2[L++]; 32 else qr3[i]=qr2[R++]; 33 } 34 for(int i=l; i<=r; ++i)qr2[i]=qr3[i]; 35 } 36 37 void cdq1(int l,int r) { 38 if(l==r)return; 39 int mid=(l+r)>>1; 40 cdq1(l,mid),cdq1(mid+1,r); 41 int L=l,R=mid+1,m=0; 42 for(; R<=r; ++R)if(qr[R].f) { 43 for(; L<=mid&&qr[L].x<=qr[R].x; ++L)if(!qr[L].f)qr2[m++]=qr[L]; 44 qr2[m++]=qr[R]; 45 } 46 if(m>0)cdq2(0,m-1); 47 L=l,R=mid+1; 48 for(int i=l; i<=r; ++i) { 49 if(R>r||(L<=mid&&qr[L].x<qr[R].x))qr2[i]=qr[L++]; 50 else qr2[i]=qr[R++]; 51 } 52 for(int i=l; i<=r; ++i)qr[i]=qr2[i]; 53 } 54 55 int main() { 56 int T; 57 scanf("%d",&T); 58 while(T--) { 59 nq=tot=0; 60 memset(c,0,sizeof c); 61 memset(ans,0,sizeof ans); 62 scanf("%d",&n); 63 for(int i=0; i<n; ++i) { 64 int f; 65 scanf("%d",&f); 66 if(f==1) { 67 int x,y,z; 68 scanf("%d%d%d",&x,&y,&z); 69 qr[nq++]= {0,x,y,z,0}; 70 } else { 71 int x1,y1,z1,x2,y2,z2; 72 scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2); 73 qr[nq++]= {1,x2,y2,z2,tot}; 74 qr[nq++]= {-1,x1-1,y2,z2,tot}; 75 qr[nq++]= {-1,x2,y1-1,z2,tot}; 76 qr[nq++]= {-1,x2,y2,z1-1,tot}; 77 qr[nq++]= {1,x1-1,y1-1,z2,tot}; 78 qr[nq++]= {1,x2,y1-1,z1-1,tot}; 79 qr[nq++]= {1,x1-1,y2,z1-1,tot}; 80 qr[nq++]= {-1,x1-1,y1-1,z1-1,tot++}; 81 } 82 } 83 maxz=0; 84 for(int i=0; i<nq; ++i)zz[maxz++]=qr[i].z; 85 sort(zz,zz+maxz); 86 maxz=unique(zz,zz+maxz)-zz; 87 for(int i=0; i<nq; ++i)qr[i].z=lower_bound(zz,zz+maxz,qr[i].z)-zz+1; 88 cdq1(0,nq-1); 89 for(int i=0; i<tot; ++i)printf("%d\n",ans[i]); 90 } 91 return 0; 92 }
解法二(三重CDQ,无需离散化):
1)2)3)同解法一,第四步将q2中每个子区间按z坐标从小到大排序,将左区间元素与右区间查询放入qr3中,然后利用类似归并排序求逆序对的方法对qr3中的贡献进行统计
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 const int N=5e5+10; 5 struct QR { 6 int f,x,y,z,i; 7 } qr[N],qr2[N],qr3[N],qr4[N]; 8 int n,ans[N],nq,tot; 9 10 void cdq3(int l,int r) { 11 if(l==r)return; 12 int mid=(l+r)>>1; 13 cdq3(l,mid),cdq3(mid+1,r); 14 int L=l,R=mid+1,m=0; 15 for(; R<=r; ++R)if(qr3[R].f) { 16 for(; L<=mid&&qr3[L].z<=qr3[R].z; ++L)if(!qr3[L].f)m++; 17 ans[qr3[R].i]+=m*qr3[R].f; 18 } 19 L=l,R=mid+1; 20 for(int i=l; i<=r; ++i) { 21 if(R>r||(L<=mid&&qr3[L].z<=qr3[R].z))qr4[i]=qr3[L++]; 22 else qr4[i]=qr3[R++]; 23 } 24 for(int i=l; i<=r; ++i)qr3[i]=qr4[i]; 25 } 26 27 28 void cdq2(int l,int r) { 29 if(l==r)return; 30 int mid=(l+r)>>1; 31 cdq2(l,mid),cdq2(mid+1,r); 32 int L=l,R=mid+1,m=0; 33 for(; R<=r; ++R)if(qr2[R].f) { 34 for(; L<=mid&&qr2[L].y<=qr2[R].y; ++L)if(!qr2[L].f)qr3[m++]=qr2[L]; 35 qr3[m++]=qr2[R]; 36 } 37 if(m>0)cdq3(0,m-1); 38 L=l,R=mid+1; 39 for(int i=l; i<=r; ++i) { 40 if(R>r||(L<=mid&&qr2[L].y<=qr2[R].y))qr3[i]=qr2[L++]; 41 else qr3[i]=qr2[R++]; 42 } 43 for(int i=l; i<=r; ++i)qr2[i]=qr3[i]; 44 } 45 46 void cdq1(int l,int r) { 47 if(l==r)return; 48 int mid=(l+r)>>1; 49 cdq1(l,mid),cdq1(mid+1,r); 50 int L=l,R=mid+1,m=0; 51 for(; R<=r; ++R)if(qr[R].f) { 52 for(; L<=mid&&qr[L].x<=qr[R].x; ++L)if(!qr[L].f)qr2[m++]=qr[L]; 53 qr2[m++]=qr[R]; 54 } 55 if(m>0)cdq2(0,m-1); 56 L=l,R=mid+1; 57 for(int i=l; i<=r; ++i) { 58 if(R>r||(L<=mid&&qr[L].x<qr[R].x))qr2[i]=qr[L++]; 59 else qr2[i]=qr[R++]; 60 } 61 for(int i=l; i<=r; ++i)qr[i]=qr2[i]; 62 } 63 64 int main() { 65 int T; 66 scanf("%d",&T); 67 while(T--) { 68 nq=tot=0; 69 memset(ans,0,sizeof ans); 70 scanf("%d",&n); 71 for(int i=0; i<n; ++i) { 72 int f; 73 scanf("%d",&f); 74 if(f==1) { 75 int x,y,z; 76 scanf("%d%d%d",&x,&y,&z); 77 qr[nq++]= {0,x,y,z,0}; 78 } else { 79 int x1,y1,z1,x2,y2,z2; 80 scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2); 81 qr[nq++]= {1,x2,y2,z2,tot}; 82 qr[nq++]= {-1,x1-1,y2,z2,tot}; 83 qr[nq++]= {-1,x2,y1-1,z2,tot}; 84 qr[nq++]= {-1,x2,y2,z1-1,tot}; 85 qr[nq++]= {1,x1-1,y1-1,z2,tot}; 86 qr[nq++]= {1,x2,y1-1,z1-1,tot}; 87 qr[nq++]= {1,x1-1,y2,z1-1,tot}; 88 qr[nq++]= {-1,x1-1,y1-1,z1-1,tot++}; 89 } 90 } 91 cdq1(0,nq-1); 92 for(int i=0; i<tot; ++i)printf("%d\n",ans[i]); 93 } 94 return 0; 95 }
两种解法复杂度均为O(nlog3n),但解法二比解法一常数大很多,这道题可以勉强A掉,而同样思路的BZOJ3262用同样的方法就会被卡掉。
原文地址:https://www.cnblogs.com/asdfsag/p/10269495.html
时间: 2024-10-06 14:22:43