BZOJ3787 gty的文艺妹子序列 【树状数组】【分块】
题目分析:
首先这种乱七八糟的题目就分块。然后考虑逆序对的统计。
一是块内的,二是块之间的,三是一个块内一个块外,四是都在块外。
令分块大小为$S$。
块内的容易维护,单次维护时间是$O(S)$。
块之间的有两种维护方法,一种是在块内维持有序,那么修改的时候进行一次插排,查询的时候枚举每一块,然后二分查找;另一种是利用下面所述的另一个数组来做块内统计。第一种方法的时间是$O(S+\frac{n}{S}\log S)$;第二种是$O(\frac{n}{S}logn)$.这里我们需要用树状数组维护,但是树状数组带的$\log$与查找是独立的。
一个在块内一个在块外的通过枚举块外的,然后利用数组$f[i][j]$记录$1 \sim i$块小于等于$j$的数的个数,这里用树状数组维护前缀和。时间复杂度是$O(S \log n)$.
最后一部分单独提取出来求逆序对,时间$O(SlogS)$.
那么$O(Slogn) = O(\frac{n}{S}logn)$可以解得$S = O(\sqrt{n})$.
所以这样做的时间复杂度是$O(n\sqrt{n}logn)$
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int srt = 250; 5 const int maxn = 50100; 6 7 int n,m; 8 int c[srt+5][maxn],inside[maxn],con[srt+5][srt+5]; 9 int a[maxn],ord[maxn]; 10 11 int lowbit(int x){return x&-x;} 12 13 void add(int now,int dr,int om){while(now <= n)c[om][now]+=dr,now+=lowbit(now);} 14 int query(int now,int om){ 15 int ans = 0; 16 while(now){ans += c[om][now]; now -= lowbit(now);} 17 return ans; 18 } 19 void Add(int now,int dr,int om){while(now<=n/srt+1){con[om][now]+=dr;now += lowbit(now);}} 20 int Query(int now,int om){ 21 int ans = 0; 22 while(now){ans += con[om][now]; now -= lowbit(now);} 23 return ans; 24 } 25 26 void read(){ 27 scanf("%d",&n); 28 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 29 scanf("%d",&m); 30 } 31 32 void init(){ 33 for(int i=1,cnt=1;i<=n;i+=srt,cnt++){ 34 memset(c[0],0,sizeof(c[0])); 35 for(int j=srt-1;j>=0;j--){ 36 if(j+i > n) continue; 37 inside[cnt] += query(a[i+j]-1,0); 38 add(a[i+j],1,0); 39 } 40 } 41 for(int i=1;(i-1)*srt+1<=n;i++){ 42 memset(c[0],0,sizeof(c[0])); 43 for(int j=(i-1)*srt+1;j<=min(n,i*srt);j++) add(a[j],1,0); 44 for(int j=i+1;(j-1)*srt+1<=n;j++){ 45 for(int k=(j-1)*srt+1;k<=min(n,j*srt);k++) 46 con[i][j] += query(n,0)-query(a[k],0); 47 } 48 } 49 for(int i=1;(i-1)*srt+1<=n;i++){ 50 int j; for(j=i+1;(j-1)*srt+1<=n;j++); 51 for(;j>i;j--){ int z = con[i][j]; con[i][j] = 0; Add(j,z,i); } 52 for(int j=(i-1)*srt+1;j<=min(n,i*srt);j++){ 53 for(int k=i;(k-1)*srt+1<=n;k++) add(a[j],1,k); 54 } 55 } 56 } 57 58 void work(){ 59 int lastans = 0;memset(c[0],0,sizeof(c[0])); 60 for(int i=1;i<=m;i++){ 61 int pv; scanf("%d",&pv); 62 if(pv == 0){ 63 int l,r; scanf("%d%d",&l,&r); l^=lastans; r^=lastans; 64 if(r-l < srt){ 65 int ans = 0; 66 for(int j=r;j>=l;j--){ans += query(a[j]-1,0);add(a[j],1,0);} 67 for(int j=r;j>=l;j--){add(a[j],-1,0);} 68 printf("%d\n",ans);lastans = ans; 69 continue; 70 } 71 int st=1,ed=1; 72 while((st-1)*srt+1 < l)st++; while(ed*srt<=r)ed++;ed--; 73 int ans = 0; for(int j=st;j<=ed;j++)ans += inside[j]; 74 for(int j=st;j<=ed;j++){ans += Query(ed,j);} 75 for(int j=l;j%srt!=1;j++)ans+=query(a[j]-1,ed)-query(a[j]-1,st-1); 76 for(int j=ed*srt+1;j<=r;j++){ 77 ans += (query(n,ed)-query(n,st-1)); 78 ans -= (query(a[j],ed)-query(a[j],st-1)); 79 } 80 for(int j=r;j>ed*srt;j--){ans += query(a[j]-1,0); add(a[j],1,0);} 81 for(int j=(st-1)*srt;j>=l;j--){ans+=query(a[j]-1,0);add(a[j],1,0);} 82 for(int j=r;j>ed*srt;j--) add(a[j],-1,0); 83 for(int j=(st-1)*srt;j>=l;j--) add(a[j],-1,0); 84 printf("%d\n",ans);lastans = ans; 85 }else{ 86 int p,v; scanf("%d%d",&p,&v);p^=lastans,v ^= lastans; 87 int bel = p/srt+(p%srt!=0); 88 for(int j=(bel-1)*srt+1;j<p;j++){ 89 if(a[j] > a[p]) inside[bel]--; if(a[j] > v) inside[bel]++; 90 } 91 for(int j=p+1;j<=bel*srt;j++){ 92 if(a[j] < a[p]) inside[bel]--; if(a[j] < v) inside[bel]++; 93 } 94 for(int j=1;j<bel;j++){ 95 int z = (srt-query(a[p],j)+query(a[p],j-1)); 96 int zz = (srt-query(v,j)+query(v,j-1)); 97 Add(bel,zz-z,j); 98 } 99 for(int j=bel+1;(j-1)*srt+1<=n;j++){ 100 int z=query(a[p]-1,j)-query(a[p]-1,j-1); 101 int r=query(v-1,j)-query(v-1,j-1); 102 Add(j,r-z,bel); 103 } 104 for(int j=bel;(j-1)*srt+1<=n;j++){add(a[p],-1,j); add(v,1,j);} 105 a[p] = v; 106 } 107 } 108 } 109 110 int main(){ 111 read(); 112 init(); 113 work(); 114 return 0; 115 }