bzoj 3295: [Cqoi2011]动态逆序对(树套树 or CDQ分治)
Posted Swm_sxt
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 3295: [Cqoi2011]动态逆序对(树套树 or CDQ分治)相关的知识,希望对你有一定的参考价值。
Description
对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。
Input
输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。
Output
输出包含m行,依次为删除每个元素之前,逆序对的个数。
Sample Input
5 4
1
5
3
4
2
5
1
4
2
1
5
3
4
2
5
1
4
2
Sample Output
5
2
2
1
2
2
1
各种方法都可做
树套树(5.9s)
#include<cstdio> #include<cstdlib> #include<algorithm> using namespace std; int n,m,l,r,o,p,num=0; long long ans=0; inline int read(){ p=0;o=getchar(); while(o<‘0‘||o>‘9‘) o=getchar(); while(o>=‘0‘&&o<=‘9‘) p=p*10+o-48,o=getchar(); return p; } int root[100001],a[100001],tt[100001]; struct tree{ int l,r,k; tree(){ k=0; } }; tree t[10000000]; inline void insert(int &p,int l,int r,int k){ if (p==0) p=++num; t[p].k++; if (l==r) return; int mid=l+r>>1; if (k<=mid) insert(t[p].l,l,mid,k);else insert(t[p].r,mid+1,r,k); } inline void del(int p,int l,int r,int k){ t[p].k--; if (l==r) return; int mid=l+r>>1; if (k<=mid) del(t[p].l,l,mid,k);else del(t[p].r,mid+1,r,k); } inline int qui(int p,int l,int r,int k){ if (p==0) return 0; if (r==k) return t[p].k; int mid=l+r>>1; if (k<=mid) return qui(t[p].l,l,mid,k);else return qui(t[p].r,mid+1,r,k)+(t[p].l==0?0:t[t[p].l].k); } inline int qua(int p,int l,int r,int k){ if (p==0) return 0; if (l==k) return t[p].k; int mid=l+r>>1; if (k<=mid) return qua(t[p].l,l,mid,k)+(t[p].r==0?0:t[t[p].r].k);else return qua(t[p].r,mid+1,r,k); } inline int lo(int x){return x&(-x);} inline void in(int i,int k){ while(i<=n){ insert(root[i],1,n,k); i+=lo(i); } } inline void de(int i,int k){ while(i<=n){ del(root[i],1,n,k); i+=lo(i); } } inline long long ask(int x,int k){ long long s=0; k++; while(x>0){ if (k<=n) s+=qua(root[x],1,n,k); x-=lo(x); } return s; } inline long long aski(int x,int k){ long long s=0; k--; while(x>0){ if (k>=1) s+=qui(root[x],1,n,k); x-=lo(x); } return s; } int main(){ register int i,j; n=read(); m=read(); for (i=1;i<=n;i++) in(i,a[i]=read()),tt[a[i]]=i; for (i=1;i<=n;i++) ans+=ask(i,a[i]); while(m--){ printf("%lld\n",ans); l=read();r=tt[l]; if (a[r]==0) continue;a[r]=0; ans-=ask(r,l)+aski(n,l)-aski(r,l); de(r,l); } }
CDQ分治
#include<cstdio> #include<algorithm> using namespace std; int read_p,read_ca,pr_num,pr_ch[1000]; inline int read(){ read_p=0;read_ca=getchar(); while(read_ca<‘0‘||read_ca>‘9‘) read_ca=getchar(); while(read_ca>=‘0‘&&read_ca<=‘9‘) read_p=read_p*10+read_ca-48,read_ca=getchar(); return read_p; } inline void pr(long long k){ pr_num=0; while(k>0) pr_ch[++pr_num]=k%10,k/=10; while(pr_num) putchar(pr_ch[pr_num--]+48); putchar(‘\n‘); } struct na{ int x,y,t; }b[100001],o[100001],y[100001]; int n,m,u[100001],ti[100001],s[100001]; long long ans[100001][2]; inline int low(int x){return x&(-x);} inline void add(int x){ while (x<=n){ s[x]++; x+=low(x); } } inline void del(int x){ while (x<=n){ s[x]--; x+=low(x); } } inline int ask(int x){ int ans=0; while (x>0){ ans+=s[x]; x-=low(x); } return ans; } inline bool cmp(na a,na b){ if ((a.x==b.x)&&(a.y==b.y)) return a.t<b.t; if (a.x==b.x) return a.y>b.y; return a.x<b.x; } inline bool tmp(na a,na b){ if ((a.x==b.x)&&(a.y==b.y)) return a.t<b.t; if (a.x==b.x) return a.y<b.y; return a.x>b.x; } inline void work0(int l,int r){ if (l==r) return; int mid=l+r>>1,ll=l-1,rr=mid; for (register int i=l;i<=r;i++){ if (b[i].t<=mid) add(n-b[i].y+1); if (b[i].t>mid) ans[b[i].t][0]+=ask(n-b[i].y+1); } for (register int i=l;i<=r;i++) if (b[i].t<=mid) o[++ll]=b[i];else o[++rr]=b[i]; for (register int i=l;i<=r;i++) b[i]=o[i]; for (register int i=l;i<=r;i++) if (b[i].t<=mid) del(n-b[i].y+1); work0(l,mid);work0(mid+1,r); } inline void work1(int l,int r){ if (l==r) return; int mid=l+r>>1,ll=l-1,rr=mid; for (register int i=l;i<=r;i++){ if (y[i].t<=mid) add(y[i].y); if (y[i].t>mid) ans[y[i].t][1]+=ask(y[i].y); } for (register int i=l;i<=r;i++) if (y[i].t<=mid) del(y[i].y); for (register int i=l;i<=r;i++) if (y[i].t<=mid) o[++ll]=y[i];else o[++rr]=y[i]; for (register int i=l;i<=r;i++) y[i]=o[i]; work1(l,mid);work1(mid+1,r); } int main(){ register int i,j=0; n=read();m=read(); for (i=1;i<=n;i++) u[read()]=i; for (i=0;i<m;i++) ti[read()]=m-i; for (i=1;i<=n;i++){ if (ti[i]==0) b[i].t=++j;else b[i].t=n-m+ti[i]; b[i].x=u[i];b[i].y=i; y[i]=b[i]; } sort(b+1,b+n+1,cmp); sort(y+1,y+n+1,tmp); work0(1,n);work1(1,n); for (int i=2;i<=n;i++) ans[i][0]+=ans[i-1][0],ans[i][1]+=ans[i-1][1]; for (int i=n;i>j;i--) pr(ans[i][0]+ans[i][1]); }
以上是关于bzoj 3295: [Cqoi2011]动态逆序对(树套树 or CDQ分治)的主要内容,如果未能解决你的问题,请参考以下文章