BZOJ 3295: [Cqoi2011]动态逆序对 [CDQ分治]
RT
首先可以看成倒着插入,求逆序对数
每个数分配时间(注意每个数都要一个时间)$t$,$x$位置,$y$数值
$CDQ(l,r)$时归并排序$x$
然后用$[l,mid]$的加入更新$[mid+1,r]$的查询(其实每个数就是一个插入一个查询)
这里就是前后求逆序对,用树状数组
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; typedef long long ll; const int N=2e5+5; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n,m; int mp[N]; struct Operation{ int t,x,y; Operation(){} Operation(int t,int id,int v):t(t),x(id),y(v){} bool operator <(const Operation &r)const{ return x==r.x ? y<r.y : x<r.x; } }a[N],t[N]; inline bool cmpTime(const Operation &a,const Operation &b){ return a.t==b.t ? a.x<b.x : a.t<b.t; } int c[N]; inline int lowbit(int x){return x&-x;} inline void add(int p,int v){for(;p<=n;p+=lowbit(p)) c[p]+=v;} inline int sum(int p){ int re=0; for(;p;p-=lowbit(p)) re+=c[p]; return re; } ll ans[N]; void CDQ(int l,int r){ if(l==r) return; int mid=(l+r)>>1; CDQ(l,mid);CDQ(mid+1,r); int i=l,j=mid+1,p=l; while(i<=mid||j<=r){ if(j>r||(i<=mid&&a[i]<a[j])) add(a[i].y,1),t[p++]=a[i++]; else ans[a[j].t]+=sum(n)-sum(a[j].y),t[p++]=a[j++]; } for(int i=l;i<=mid;i++) add(a[i].y,-1); for(int i=l;i<=r;i++) a[i]=t[i]; for(int i=r;i>=l;i--){ if(a[i].t<=mid) add(a[i].y,1); else ans[a[i].t]+=sum(a[i].y); } for(int i=l;i<=r;i++) if(a[i].t<=mid) add(a[i].y,-1); } int main(){ //freopen("inverse.in","r",stdin); //freopen("inverse.out","w",stdout); n=read();m=read(); for(int i=1;i<=n;i++) a[i]=Operation(0,i,read()),mp[a[i].y]=i; int Tim=n; for(int i=1;i<=m;i++) a[mp[read()]].t=Tim--; for(int i=1;i<=n;i++) if(!a[i].t) a[i].t=Tim--; sort(a+1,a+1+n,cmpTime); //for(int i=1;i<=10;i++) printf("hi %d %d %d\n",i,a[i].t,a[i].y); CDQ(1,n); //for(int i=1;i<=10;i++) printf("ans %d %d\n",i,ans[i]); for(int i=1;i<=n;i++) ans[i]+=ans[i-1]; for(int i=n;i>=n-m+1;i--) printf("%lld\n",ans[i]); }
【update 2017-03-17】
前两天学到了删除的姿势,逆序对问题的删除操作不用时间倒流也可以,直接减去它形成的逆序对数并且在树状数组中删除就可以了
虽然慢一些但是清晰多了
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; typedef long long ll; const int N=2e5+5; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n,Q,a[N],pos[N],x; int m,tim; struct meow{ int t,x,y,type,qid; meow(){} meow(int a,int b,int c,int d,int e=0):t(a),x(b),y(c),type(d),qid(e){} bool operator <(const meow &r) const{ return x==r.x ? y<r.y : x<r.x; } }q[N],t[N]; ll ans[N]; int c[N]; inline void add(int p,int v) {for(;p<=n;p+=(p&-p)) c[p]+=v;} inline int sum(int p) {int re=0; for(;p;p-=(p&-p)) re+=c[p]; return re;} void CDQ(int l,int r){ if(l==r) return; int mid=(l+r)>>1; for(int i=l;i<=r;i++){ if(q[i].t<=mid) add(q[i].y,q[i].type); else ans[q[i].qid]+= q[i].type*( sum(n)-sum(q[i].y) ); } for(int i=l;i<=r;i++) if(q[i].t<=mid) add(q[i].y,-q[i].type); for(int i=r;i>=l;i--){ if(q[i].t<=mid) add(q[i].y,q[i].type); else ans[q[i].qid]+= q[i].type*sum(q[i].y-1); } for(int i=l;i<=r;i++) if(q[i].t<=mid) add(q[i].y,-q[i].type); int p1=l,p2=mid+1; for(int i=l;i<=r;i++){ if(q[i].t<=mid) t[p1++]=q[i]; else t[p2++]=q[i]; } for(int i=l;i<=r;i++) q[i]=t[i]; CDQ(l,mid); CDQ(mid+1,r); } int main(){ freopen("in","r",stdin); n=read(); Q=read(); for(int i=1;i<=n;i++) a[i]=read(), pos[a[i]]=i, q[++m]=meow(++tim, i, a[i], 1, 0); for(int i=1;i<=Q;i++) x=read(), q[++m]=meow(++tim, pos[x], x, -1, i); sort(q+1, q+1+m); CDQ(1,m); for(int i=1;i<=Q;i++) ans[i]+=ans[i-1],printf("%lld\n",ans[i-1]); }
Copyright:http://www.cnblogs.com/candy99/