【模板】CDQ分治

__stdcall大佬的讲解

这里贴的代码写的是点修改、区间查询的题。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define LL long long
 5 #define rg register
 6 #define N 2000010
 7 #define mid ((l+r)>>1)
 8 using namespace std;
 9 int n,m,cnt,tot,ans[N];
10 struct rec{
11     int pos,val,type;
12     //对于修改操作,val表示增量,对于查询操作,val表示它是第几个询问;
13     //type为0表示修改,1表示区间左端点(开),2表示区间右端点 
14     bool operator<(const rec&x)const{return pos==x.pos?type<x.type:pos<x.pos;}
15 }a[N],tmp[N];
16 inline int read(){
17     int k=0,f=1; char c=getchar();
18     while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
19     while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar();
20     return k*f;
21 }
22 void cdq(int l,int r){
23     if(l>=r) return;
24     cdq(l,mid),cdq(mid+1,r);
25     LL sum=0; int p1=l,p2=mid+1,cnt=0;
26     while(p1<=mid&&p2<=r){
27         if(a[p1]<a[p2]){
28             if(!a[p1].type) sum+=a[p1].val; tmp[++cnt]=a[p1++];
29         }
30         else{
31             if(a[p2].type==1) ans[a[p2].val]-=sum;
32             else if(a[p2].type==2) ans[a[p2].val]+=sum;
33             tmp[++cnt]=a[p2++];
34         }
35     }
36     for(rg int i=p1;i<=mid;i++) tmp[++cnt]=a[i];
37     for(rg int i=p2;i<=r;i++){
38         if(a[i].type==1) ans[a[i].val]-=sum;
39         else if(a[i].type==2) ans[a[i].val]+=sum;
40         tmp[++cnt]=a[i];
41     }
42     for(rg int i=l;i<=r;i++) a[i]=tmp[i-l+1];
43 }
44 int main(){
45     n=read(); m=read();
46     for(rg int i=1;i<=n;i++) a[++tot]=(rec){i,read(),0};
47     for(rg int i=1;i<=m;i++){
48         int opt=read(),x=read(),y=read();
49         if(opt==1) a[++tot]=(rec){x,y,0};
50         else a[++tot]=(rec){x-1,++cnt,1},a[++tot]=(rec){y,cnt,2};
51     }
52     cdq(1,tot);
53     for(rg int i=1;i<=cnt;i++) printf("%d\n",ans[i]);
54 }
55  

 

posted @ 2018-11-08 21:59  Driver_Lao  阅读(191)  评论(0编辑  收藏  举报