这题说的是给了三维空间然后操作 寻求在 x1,y1,z1 x2, y2, z2; (x1<x2, y1<y2,z1<z2) 计算出在 以这两个端点为右下和左上端点的方体内的点的个数。CDQ 分治第一次听说,
在一个方体内使用容斥原理,然后不断的将剩下的点分成两个部分,然后这样不断地下去,对于每个部分在进行一次CDQ然后,再使用BIT求解,这样我们可以看看他这神奇的CDQ,他先是这样的,第一次CDQ先对在区间内的点进行x轴排序,排完后然后将这些点按照y轴进行合并,这样做的好处是想想二分后的一部分在一侧另一部分只会用到前一部分的,用这种方法可以让后面的所有的点都得到他被包含的查询内、
cdq套cdq套bit
#include <iostream> #include <cstdio> #include <algorithm> #include <string.h> using namespace std; const int maxn=50005; struct point{ int x,y,z,delt,qnum,kind; point(){} point(int a,int b, int c,int d,int e,int f){ this->x=a;this->y=b;this->z=c;this->delt=d; this->qnum=e; this->kind=f; } }star[maxn*8],start3[maxn*8]; int Z[maxn*8],tot,qnum,ans[maxn*8],N,C[maxn*8]; bool use[maxn*8]; int lowbit(int x){ return x&(-x); } void aDD(int loc, int val){ while(loc<=N){ C[loc]+=val; loc+=lowbit(loc); } } int sum(int loc){ int s=0; while(loc>0){ s+=C[loc]; loc-=lowbit(loc); } return s; } void add(int x,int y,int z,int delt,int qnum,int kind ){ star[tot]=point(x,y,z,delt,qnum,kind); Z[tot]=z;++tot; } void scatter(){ sort(Z,Z+tot); N=unique(Z,Z+tot)-Z; for(int i=0; i<tot; ++i) star[i].z=lower_bound(Z,Z+N,star[i].z)-Z+1; } bool cmp1(point A, point B){ return A.x<B.x||(A.x==B.x&&A.qnum<B.qnum); } bool cmp2(point A, point B){ return A.y<B.y||(A.y==B.y&&A.qnum<B.qnum); } void CDQ2(int L, int R){ if(L>=R) return ; int mid=(R+L)>>1; CDQ2(L,mid); CDQ2(mid+1,R); int j=L; for(int i=mid+1;i<=R; ++i){ for( ;j<=mid && ( start3[j].y <= start3[i].y ) ; ++j ) if(start3[j].kind==0){ aDD(start3[j].z,start3[j].delt); } ans[start3[i].qnum]+=sum(start3[i].z)*start3[i].delt; } for(int i=L; i<j; ++i) if(start3[i].kind==0) aDD(start3[i].z,-start3[i].delt); inplace_merge(start3+L,start3+mid+1,start3+R+1,cmp2); } void CDQ1(int L, int R){ if(L>=R) return ; int mid =(L+R)>>1; CDQ1(L, mid ); CDQ1(mid+1,R); int num=0; for(int i=L; i<=mid; ++i) if(star[i].kind==0) start3[num++]=star[i]; for(int i=mid+1;i<=R; ++i) if(star[i].kind==1) start3[num++]=star[i]; sort(start3,start3+num,cmp1); CDQ2(0,num-1); } int main() { int cas; scanf("%d",&cas); memset(use,false,sizeof(use)); memset(ans,0,sizeof(ans)); while(cas--){ int Q ; tot=qnum=0; scanf("%d",&Q); for(int i=0; i<Q; ++i){ int A; scanf("%d",&A); if(A==1){ int x,y,z; scanf("%d%d%d",&x,&y,&z); add( x, y, z, 1, qnum, 0);qnum++; }else{ int x1,y1,z1,x2,y2,z2; use[qnum]=true; scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2); add(x1-1,y1-1,z1-1,-1,qnum,1); add(x1-1,y1-1,z2 , 1,qnum,1); add(x1-1,y2 ,z1-1, 1,qnum,1); add(x1-1,y2 ,z2 ,-1,qnum,1); add(x2 ,y2 ,z1-1,-1,qnum,1); add(x2 ,y2 ,z2 , 1,qnum,1); add(x2 ,y1-1,z1-1, 1,qnum,1); add(x2 ,y1-1, z2,-1,qnum,1); qnum++; } } scatter(); CDQ1(0,tot-1); for(int i=0; i<qnum; ++i){ if(use[i]==true) printf("%d ",ans[i]); use[i]=false; ans[i]=0; } } return 0; }
这里有一个方法使用cdq里面套了一个BIT 然后套 了一个Treap 使用cdq分治,然后离散了x 然后在BiT上放上棵Treap,通过Treap 去找到对应的个数
#include <iostream> #include <cstdio> #include <algorithm> #include <string.h> #include <cstdlib> using namespace std; const int maxn=50000+10; struct Node{ Node *ch[2]; int r; int y; int spoint; int loc; void maintain(){ spoint=loc; if(ch[0]!=NULL) spoint+=ch[0]->spoint; if(ch[1]!=NULL) spoint+=ch[1]->spoint; } Node(int v):y(v){ r=rand(); spoint=1; loc=1; ch[0]=ch[1]=NULL; } int cmp(int x){ if(x==y) return -1; return x<y?0:1; } }; Node *T[maxn*3]; int now[maxn*3],Time; void removetree(Node *&o){ if(o->ch[0]!=NULL) removetree(o->ch[0]); if(o->ch[1]!=NULL) removetree(o->ch[1]); delete o; o=NULL; } void rotate(Node *&o, int d){ Node *k=o->ch[d^1]; o->ch[d^1]=k->ch[d]; k->ch[d]=o; o->maintain(); k->maintain(); o=k; } void insert(Node *&o, int y){ if(o==NULL){ o=new Node(y); }else{ int d=o->cmp(y); if(d==-1){ o->loc++; }else{ insert(o->ch[d],y); if( o->ch[d]->r > o->r ) rotate(o,d^1); } } o->maintain(); } struct point{ int x1,x2,y1,y2,z; int op,q; point(int x1=0,int y1=0,int x2=0, int y2=0,int z=0, int op=0, int q=0){ this->x1=x1;this->y1=y1; this->x2=x2;this->y2=y2; this->z=z; this->op=op; this->q=q; } }P[maxn*3],s1[maxn*3]; int cntx[maxn*3],ans[maxn],point_cnt,x_cnt; bool vis[maxn]; bool cmp(point A, point B){ if(A.z!=B.z)return A.z<B.z; return A.q<B.q; } int lowbit(int x){ return x&(-x); } void add(int loc, int y){ while(loc<=x_cnt){ if( now[ loc ] != Time ){ if(T[loc]!=NULL)removetree(T[loc]); T[loc]=NULL; now[loc]=Time; } insert(T[loc],y); loc+=lowbit(loc); } } int search(Node *&o , int y){ if(o==NULL) return 0; if(y<o->y) return search(o->ch[0],y); else { int a=search(o->ch[1],y); if(o->ch[0]!=NULL) a+=o->ch[0]->spoint; a+=o->loc; return a; } } int sum(int loc, int y){ int ans=0; while(loc>0){ if(now[loc]==Time) ans+=search(T[loc],y); loc-=lowbit(loc); } return ans; } void cdq_fz(int L, int R){ if(L>=R) return ; int mid=(L+R)/2; int e=0; cdq_fz( L, mid ); cdq_fz( mid+1, R ); for(int i=L; i<=mid; ++i) if(P[i].q==0) s1[e++]=P[i]; for(int i=mid+1; i<=R; ++i) if(P[i].q!=0) s1[e++]=P[i]; sort(s1,s1+e,cmp); Time++; for(int i=0; i<e; ++i) if(s1[i].q==0){ add(s1[i].x2,s1[i].y2); }else{ ans[s1[i].q]+=s1[i].op*sum(s1[i].x2, s1[i].y2); ans[s1[i].q]-=s1[i].op*sum(s1[i].x1, s1[i].y2); ans[s1[i].q]-=s1[i].op*sum(s1[i].x2, s1[i].y1); ans[s1[i].q]+=s1[i].op*sum(s1[i].x1, s1[i].y1); } } void solve(){ int N; scanf("%d",&N); for(int cc=1; cc<=N; ++cc){ int op,x1,x2,y1,y2,z1,z2; scanf("%d",&op); if(op==1){ scanf("%d%d%d",&x1,&y1,&z1); P[point_cnt++]=point(x1,y1,x1,y1,z1,1,0); cntx[x_cnt++]=x1; vis[cc]=false; }else{ scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2); cntx[x_cnt++]=x1-1; cntx[x_cnt++]=x2; P[point_cnt++]=point(x1-1,y1-1,x2,y2, z2, 1,cc); P[point_cnt++]=point(x1-1,y1-1,x2,y2,z1-1,-1,cc); vis[cc]=true; } } sort(cntx,cntx+x_cnt); x_cnt=unique(cntx,cntx+x_cnt)-cntx; for(int i=0 ; i<point_cnt ; ++i ){ if(P[i].q!=0) P[i].x1=lower_bound(cntx,cntx+x_cnt, P[i].x1)-cntx+1; P[i].x2=lower_bound(cntx,cntx+x_cnt, P[i].x2)-cntx+1; } cdq_fz(0,point_cnt-1); for( int i=1; i<=N; ++i ) if( vis[i] ) printf("%d ",ans[i]); } int main() { int T; scanf("%d",&T); while(T--){ memset(ans,0,sizeof(ans)); memset(now,0,sizeof(now)); x_cnt = point_cnt=0; Time=1; solve(); } return 0; }