LUGOU P3374 【模板】树状数组 1(CDQ 分治)

传送门

拿个二维偏序练练cdq板子,其实就和归并排序差不多,复杂度不太会,似乎nlogn?。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>

using namespace std;
const int MAXN = 500005;
const int MAXQ = MAXN*3;
typedef long long LL;

inline LL rd(){
    LL x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
    while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return f?x:-x;
}

int n,m,cnt,num;
LL ans[MAXN];

struct Query{
    int type,id;LL val;
    friend bool operator<(const Query A,const Query B){
        return A.id==B.id?A.type<B.type:A.id<B.id;
    }
}q[MAXQ],tmp[MAXQ];

void cdq(int l,int r){
    if(l==r) return;
    int mid=l+r>>1;cdq(l,mid),cdq(mid+1,r);
    int L=l,R=mid+1;LL sum=0;int o=0;
    while(L<=mid && R<=r){
        if(q[L]<q[R]){
            if(q[L].type==1) sum+=q[L].val;
            tmp[++o]=q[L++];
        }
        else{
            if(q[R].type==2) ans[q[R].val]-=sum;
            else if(q[R].type==3) ans[q[R].val]+=sum;
            tmp[++o]=q[R++];
        }
    }
    while(L<=mid) tmp[++o]=q[L++];
    while(R<=r) {
        if(q[R].type==2) ans[q[R].val]-=sum;
        else if(q[R].type==3) ans[q[R].val]+=sum;
        tmp[++o]=q[R++];
    }
    for(int i=1;i<=o;i++) q[i+l-1]=tmp[i];
}

int main(){
    n=rd(),m=rd();
    for(int i=1;i<=n;i++)
        q[++cnt].id=i,q[cnt].type=1,q[cnt].val=rd();
    for(int i=1;i<=m;i++){
        q[++cnt].type=rd();
        if(q[cnt].type==1) q[cnt].id=rd(),q[cnt].val=rd();
        else{
            q[cnt].id=rd()-1;q[cnt].val=++num;
            q[++cnt].type=3;q[cnt].id=rd();q[cnt].val=num;
        }
    }
//    cout<<"  "<<endl;
//    for(int i=1;i<=cnt;i++) {
//        cout<<q[i].type<<" "<<q[i].id<<" "<<q[i].val<<endl;
//    }
    cdq(1,cnt);
    for(int i=1;i<=num;i++) printf("%lld\n",ans[i]);
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/sdfzsyq/p/9695069.html