LUOGU P3157 [CQOI2011]动态逆序对(CDQ 分治)
Posted sdfzsyq
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LUOGU P3157 [CQOI2011]动态逆序对(CDQ 分治)相关的知识,希望对你有一定的参考价值。
解题思路
cdq分治,将位置看做一维,修改时间看做一维,权值看做一维,然后就转化成了三维偏序,用排序+cdq+树状数组。注意算删除贡献时要做两次cdq,分别算对前面和后面的贡献。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 100005; const int MAXM = 50005; const int MAXQ = MAXN+MAXM; typedef long long LL; inline int rd(){ int 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; } LL ans,f[MAXN]; int n,m,now; struct Query{ int t,pos,id,a; LL pre,nxt; }q[MAXN],tmp[MAXN]; void add(int x,int y){ for(;x<=n;x+=x&-x) f[x]+=y; } LL query(int x){ LL ret=0; for(;x;x-=x&-x) ret+=f[x]; return ret; } void Clear(int x){ for(;x<=n;x+=x&-x) f[x]=0; } inline bool cmp(Query A,Query B){ return A.a>B.a; } inline bool _cmp(Query A,Query B){ return A.a<B.a; } inline bool cmp_(Query A,Query B){ return A.pos<B.pos; } inline bool cmp1(Query A,Query B){ return A.t>B.t; } inline bool cmp2(Query A,Query B){ return A.t<B.t; } 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,o=0; while(L<=mid && R<=r){ if(q[L].pos>q[R].pos){ add(q[L].a,1); tmp[++o]=q[L++]; } else{ q[R].pre+=query(q[R].a); tmp[++o]=q[R++]; } } while(L<=mid) tmp[++o]=q[L++]; while(R<=r){ q[R].pre+=query(q[R].a); tmp[++o]=q[R++]; } for(register int i=l;i<=mid;i++) Clear(q[i].a); for(register int i=1;i<=o;i++) q[i+l-1]=tmp[i]; } 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,o=0; while(L<=mid && R<=r){ if(q[L].a>q[R].a){ add(q[L].pos,1); tmp[++o]=q[L++]; } else{ q[R].nxt+=query(q[R].pos); tmp[++o]=q[R++]; } } while(L<=mid) tmp[++o]=q[L++]; while(R<=r){ q[R].nxt+=query(q[R].pos); tmp[++o]=q[R++]; } for(register int i=l;i<=mid;i++) Clear(q[i].pos); for(register int i=1;i<=o;i++) q[i+l-1]=tmp[i]; } int main(){ n=rd(),m=rd();int x; for(int i=1;i<=n;i++) q[i].a=rd(),q[i].pos=i; sort(q+1,q+1+n,cmp); for(int i=1;i<=n;i++) { add(q[i].pos,1); ans+=query(q[i].pos-1); } for(int i=1;i<=n;i++) add(q[i].pos,-1); sort(q+1,q+1+n,_cmp); // for(int i=1;i<=n;i++) cout<<q[i].pos<<" "; // cout<<ans<<endl; for(int i=1;i<=m;i++) q[rd()].t=i; sort(q+1,q+1+n,cmp_); for(int i=1;i<=n;i++) if(q[i].t==0) q[i].t=++now+m; sort(q+1,q+1+n,cmp1); cdq(1,n); sort(q+1,q+1+n,cmp1); CDQ(1,n); sort(q+1,q+1+n,cmp2); for(int i=1;i<=m;i++) { printf("%lld ",ans); ans-=q[i].pre+q[i].nxt; } return 0; }
以上是关于LUOGU P3157 [CQOI2011]动态逆序对(CDQ 分治)的主要内容,如果未能解决你的问题,请参考以下文章
luogu P3157 [CQOI2011]动态逆序对(CDQ分治)