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;
}

 

posted @ 2018-03-08 13:55  Cupcake  阅读(157)  评论(0编辑  收藏  举报