LUGOU P3374 【模板】树状数组 1(CDQ 分治)
拿个二维偏序练练cdq板子,其实就和归并排序差不多,复杂度不太会,似乎nlogn?。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }