CDQ分治入门
用CDQ分治实现了一下树状数组的功能,初步了解了CDQ分治的基本流程。
常数大概是树状数组的一倍吧。。
CDQ分治: 左区间只处理修改,右区间只处理询问。 即,考虑左区间的修改对右区间的询问产生的影响。
#include<bits/stdc++.h> using namespace std; const int N=500010; struct Node{ int type,pos,v;//type=1表示修改,type=2表示查询左端点,type=3表示查询右端的 bool operator<(const Node& k)const{return pos==k.pos?type<k.type:pos<k.pos;} }que[N*3]; int n,m,totq,ans[N],tota; Node temp[N*3]; void cdq(int l,int r){ if(r<=l) return; int mid=(l+r)>>1; cdq(l,mid);cdq(mid+1,r); int ii=l,jj=mid+1,x=l,sum=0; while(ii<=mid&&jj<=r){ if(que[ii]<que[jj]){ if(que[ii].type==1) sum+=que[ii].v; temp[x++]=que[ii++]; }else{ if(que[jj].type!=1) ans[que[jj].v]+=(que[jj].type==3?1:-1)*sum; temp[x++]=que[jj++]; } } while(ii<=mid) temp[x++]=que[ii++]; while(jj<=r){ if(que[jj].type!=1){ ans[que[jj].v]+=(que[jj].type==3?1:-1)*sum; } temp[x++]=que[jj++]; } for(int i=l;i<=r;i++) que[i]=temp[i]; return; } int main(){ int t1,t2,opt; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&t1),que[++totq]=(Node){1,i,t1}; for(int i=1;i<=m;i++){ scanf("%d%d%d",&opt,&t1,&t2); if(opt==1){ que[++totq]=(Node){1,t1,t2}; }else{ tota++; que[++totq]=(Node){2,t1-1,tota}; que[++totq]=(Node){3,t2,tota}; } } cdq(1,totq); for(int i=1;i<=tota;i++) printf("%d\n",ans[i]); return 0; }