bzoj 3295 动态逆序对 CDQ分支
Posted SD_le
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 3295 动态逆序对 CDQ分支相关的知识,希望对你有一定的参考价值。
容易看出ans[i]=ans[i-1]-q[i],q[i]为删去第i个数减少的逆序对。
先用树状数组算出最开始的逆序对,预处理出每个数前边比它大的和后边比它小的,就求出了q[i]的初始值。
设b[i]是第i个删除的数,pos[i]为i在数列里的位置。
对q[i]产生影响的是 1. j<i,pos[b[j]]<pos[b[i]],b[j]>b[i]. 2.j<i,pos[b[j]]>pos[b[i]],b[j]<b[i].
因为是三维的,所以我们套一层cdq。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define int long long 6 #define N 100005 7 using namespace std; 8 int n,m; 9 int a[N],b[N],d[N]; 10 int c[N]; 11 int ans[N];int p[N]; 12 int qur(int x) 13 { 14 int tp=0; 15 for(int i=x;i;i-=(i&-i))tp+=c[i]; 16 return tp; 17 } 18 void add(int x,int z) 19 { 20 for(int i=x;i<=n;i+=(i&-i))c[i]+=z; 21 return ; 22 } 23 int tmp[N];int q[N]; 24 bool cmp(int x,int y) 25 { 26 return p[x]<p[y]; 27 } 28 void solve(int l,int r) 29 { 30 if(l==r)return ; 31 int mid=(l+r)>>1; 32 int cnt=0; 33 for(int i=l;i<=r;i++)tmp[++cnt]=b[i]; 34 sort(tmp+1,tmp+cnt+1,cmp); 35 for(int i=1;i<=cnt;i++) 36 { 37 if(d[tmp[i]]<=mid)add(tmp[i],1); 38 else q[tmp[i]]-=qur(n)-qur(tmp[i]); 39 } 40 for(int i=1;i<=cnt;i++)if(d[tmp[i]]<=mid)add(tmp[i],-1); 41 for(int i=cnt;i>=1;i--) 42 { 43 if(d[tmp[i]]<=mid)add(tmp[i],1); 44 else q[tmp[i]]-=qur(tmp[i]); 45 } 46 for(int i=1;i<=cnt;i++)if(d[tmp[i]]<=mid)add(tmp[i],-1); 47 solve(l,mid);solve(mid+1,r); 48 return ; 49 } 50 signed main() 51 { 52 scanf("%lld%lld",&n,&m); 53 for(int i=1;i<=n;i++)scanf("%lld",&a[i]),p[a[i]]=i; 54 for(int i=1;i<=m;i++)scanf("%lld",&b[i]),d[b[i]]=i; 55 for(int i=1;i<=n;i++) 56 { 57 int tp=qur(n)-qur(a[i]); 58 ans[0]+=tp; 59 q[a[i]]+=tp; 60 add(a[i],1); 61 } 62 memset(c,0,sizeof(c)); 63 for(int i=n;i>=1;i--) 64 { 65 int tp=qur(a[i]); 66 q[a[i]]+=tp; 67 add(a[i],1); 68 } 69 memset(c,0,sizeof(c)); 70 solve(1,m); 71 for(int i=1;i<m;i++)ans[i]=ans[i-1]-q[b[i]]; 72 for(int i=0;i<m;i++)printf("%lld\n",ans[i]); 73 return 0; 74 }
以上是关于bzoj 3295 动态逆序对 CDQ分支的主要内容,如果未能解决你的问题,请参考以下文章