[bzoj3295] [Cqoi2011]动态逆序对
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[bzoj3295] [Cqoi2011]动态逆序对相关的知识,希望对你有一定的参考价值。
数据似乎对不会cdq分治的选手极其不友好?。。。。。没错说的就是我这种上来就写树套树的傻逼>_<
先求出逆序对数,每次删除时,假设要删掉数v,v在数列中的位置为pos。那么删除后将会减少(位置在pos之前的数比v大的个数 + 位置在pos之后的数比v小的个数)个逆序对。。。挺显然的。
那就是树套树模板题了。。。然而我一开始写zkw线段树套treap,结果TLE了若干发。。毕竟数据范围10w。。。。
事实上,用树状数组套treap就可以过。。虽然有点卡时限?
然而我决定写发递归建树来爽爽。。其实就是把区间内的数排序好后,就可以O(n)建treap了(n是区间内数的个数
具体实现的话就用归并排序。。。虽然说每次直接快排复杂度也不会很高(等等我好像不会算),但是用递归排序的话就能O(nlogn)建好整个树套树了。。
然而总的时间复杂度还是O(mlog²n)= =。。。不过填了建树时间开销这个大坑
最后5s+跑完(还是很慢>_<
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #define ll long long 5 using namespace std; 6 const int maxn=100023; 7 int rt[262333],size,L[262333],R[262333]; 8 int sz[maxn*19],lc[maxn*19],rc[maxn*19],num[maxn*19],tot; 9 bool w[maxn*19]; 10 int tmp[maxn],mp[maxn],sm[maxn],pos[maxn]; 11 int i,j,n,m,k,sum; 12 ll ans; 13 14 int ra;char rx; 15 inline int read(){ 16 rx=getchar(),ra=0; 17 while(rx<‘0‘||rx>‘9‘)rx=getchar(); 18 while(rx>=‘0‘&&rx<=‘9‘)ra*=10,ra+=rx-48,rx=getchar();return ra; 19 } 20 //----------------- 21 inline void ins(int &x,int l,int r){ 22 if(l>r)return; 23 x=++tot; 24 int mid=(l+r)>>1;num[x]=mp[mid],sz[x]=r-l+1,w[x]=1; 25 if(l<r)ins(lc[x],l,mid-1),ins(rc[x],mid+1,r); 26 } 27 inline void del(int x,int v){ 28 sz[x]--; 29 if(v<num[x])del(lc[x],v);else 30 if(v>num[x])del(rc[x],v);else w[x]=0; 31 } 32 inline void qmx(int x,int v){ 33 while(x) 34 if(v<num[x])sum+=sz[rc[x]]+w[x],x=lc[x]; 35 else 36 if(v>num[x])x=rc[x]; 37 else{ 38 sum+=sz[rc[x]];break; 39 } 40 } 41 inline void qmn(int x,int v){ 42 while(x) 43 if(v<num[x])x=lc[x]; 44 else 45 if(v>num[x])sum+=sz[lc[x]]+w[x],x=rc[x]; 46 else{ 47 sum+=sz[lc[x]];break; 48 } 49 } 50 //---------------------- 51 inline int min(int a,int b){return a<b?a:b;} 52 inline int max(int a,int b){return a<b?b:a;} 53 inline void build(){ 54 register int ii,i,j,l,r,mid,sz; 55 for(i=n+size;i>size;i--)L[i]=R[i]=i-size,ins(rt[i],L[i],R[i]); 56 for(i=size<<1|1;i>n+size;i--)L[i]=n+1,R[i]=0; 57 for(ii=size;ii;ii--){ 58 if(!R[ii<<1|1]) 59 if(!R[ii<<1]){L[ii]=n+1,R[ii]=0;continue;} 60 else ins(rt[ii],L[ii<<1],R[ii<<1]),L[ii]=L[ii<<1],R[ii]=R[ii<<1]; 61 else{ 62 for(i=l=L[ii<<1],mid=R[ii<<1],j=mid+1,r=R[ii<<1|1],sz=i-1;i<=mid&&j<=r;) 63 tmp[++sz]=mp[i]<mp[j]?mp[i++]:mp[j++]; 64 while(i<=mid)tmp[++sz]=mp[i++]; 65 while(j<=r)tmp[++sz]=mp[j++]; 66 for(i=l;i<=r;i++)mp[i]=tmp[i];//归并排序 67 L[ii]=l,R[ii]=r,ins(rt[ii],L[ii],R[ii]); 68 }/原谅我乱用变量名>_< 69 } 70 } 71 inline void run(int v){ 72 int x=pos[v],y;sum=0; 73 if(x>1) 74 for(y=x-1+size,qmx(rt[y],v);y>1;y>>=1) 75 if(y&1)qmx(rt[y^1],v); 76 if(x<n) 77 for(y=x+1+size,qmn(rt[y],v);y>1;y>>=1) 78 if(!(y&1))qmn(rt[y^1],v); 79 ans-=sum; 80 for(y=x+size;y;y>>=1)del(rt[y],v); 81 } 82 83 int main(){ 84 n=read(),m=read(); 85 for(size=1;size<n;size<<=1);size--; 86 for(i=1;i<=n;i++){ 87 for(pos[j=mp[i]=read()]=i;j<=n;j+=j&(-j))ans+=sm[j]; 88 for(j=mp[i];j;j-=j&(-j))sm[j]++; 89 } 90 build(); 91 while(m--){ 92 printf("%lld\n",ans),j=read(); 93 if(m)run(j); 94 } 95 return 0; 96 }
以上是关于[bzoj3295] [Cqoi2011]动态逆序对的主要内容,如果未能解决你的问题,请参考以下文章