BZOJ 3787 Gty的文艺妹子序列(分块+树状数组+前缀和)
题意
给出n个数,要求支持单点修改和区间逆序对,强制在线。
n,m<=50000
题解
和不带修改差不多,预处理出smaller[i][j]代表前i块小于j的数的数量,但不能用f[i][j]代表第i块到第j块逆序对的数量,这样不好维护。
我们用f[i][j]代表从第i块选出一个元素与从第j块选出一个元素组成逆序对的数量,维护时最多修改根号n个f数组,查询时用前缀和起到与不带修改时f数组的作用。
其他部分和不带修改时差不多。
然后问题就解决了。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 const int N=50100; 8 int n,Block,a[N],block[N],L[300],R[300],tr1[300][300],tr[300][N],ans,m; 9 int lowbit(int x){ 10 return x&-x; 11 } 12 void add(int id,int x,int w){ 13 for(int i=x;i<=n;i+=lowbit(i)){ 14 tr[id][i]+=w; 15 } 16 } 17 int getsum(int id,int x){ 18 int tmp=0; 19 for(int i=x;i;i-=lowbit(i)){ 20 tmp+=tr[id][i]; 21 } 22 return tmp; 23 } 24 void add1(int id,int x,int w){ 25 for(int i=x;i<=block[n];i+=lowbit(i)){ 26 tr1[id][i]+=w; 27 } 28 } 29 int getsum1(int id,int x){ 30 int tmp=0; 31 for(int i=x;i;i-=lowbit(i)){ 32 tmp+=tr1[id][i]; 33 } 34 return tmp; 35 } 36 int main(){ 37 scanf("%d",&n);Block=sqrt(n); 38 for(int i=1;i<=n;i++){ 39 scanf("%d",&a[i]); 40 block[i]=(i-1)/Block+1; 41 if(!L[block[i]])L[block[i]]=i; 42 R[block[i]]=i; 43 } 44 for(int i=1;i<=block[n];i++) 45 for(int j=L[i];j<=n;j++){ 46 add(i,a[j],1); 47 } 48 for(int i=1;i<=block[n];i++){ 49 for(int j=L[i];j<=R[i];j++){ 50 add(0,a[j],1); 51 add1(i,i,getsum(0,n)-getsum(0,a[j])); 52 } 53 for(int j=R[i]+1;j<=n;j++){ 54 add1(i,block[j],getsum(0,n)-getsum(0,a[j])); 55 } 56 for(int j=L[i];j<=R[i];j++){ 57 add(0,a[j],-1); 58 } 59 } 60 scanf("%d",&m); 61 while(m--){ 62 int k,x,y; 63 scanf("%d%d%d",&k,&x,&y); 64 x^=ans;y^=ans; 65 if(k==1){ 66 for(int i=1;i<=block[x]-1;i++){ 67 int size=R[i]-L[i]+1; 68 add1(i,block[x],size-(getsum(i,y)-getsum(i+1,y))-(size-(getsum(i,a[x])-getsum(i+1,a[x])))); 69 } 70 for(int i=block[x]+1;i<=block[n];i++){ 71 add1(block[x],i,getsum(i,y-1)-getsum(i+1,y-1)-(getsum(i,a[x]-1)-getsum(i+1,a[x]-1))); 72 } 73 for(int i=L[block[x]];i<=R[block[x]];i++){ 74 add(0,a[i],1); 75 add1(block[x],block[x],-(getsum(0,n)-getsum(0,a[i]))); 76 } 77 for(int i=L[block[x]];i<=R[block[x]];i++){ 78 add(0,a[i],-1); 79 } 80 for(int i=1;i<=block[x];i++){ 81 add(i,a[x],-1);add(i,y,1); 82 } 83 a[x]=y; 84 for(int i=L[block[x]];i<=R[block[x]];i++){ 85 add(0,a[i],1); 86 add1(block[x],block[x],getsum(0,n)-getsum(0,a[i])); 87 } 88 for(int i=L[block[x]];i<=R[block[x]];i++){ 89 add(0,a[i],-1); 90 } 91 } 92 else{ 93 if(block[x]+1>=block[y]){ 94 ans=0; 95 for(int i=x;i<=y;i++){ 96 add(0,a[i],1); 97 ans+=getsum(0,n)-getsum(0,a[i]); 98 } 99 for(int i=x;i<=y;i++){ 100 add(0,a[i],-1); 101 } 102 printf("%d\n",ans); 103 } 104 else{ 105 ans=0; 106 for(int i=block[x]+1;i<=block[y]-1;i++){ 107 ans+=getsum1(i,block[y]-1); 108 } 109 for(int i=x;i<=R[block[x]];i++){ 110 add(0,a[i],1); 111 ans+=getsum(0,n)-getsum(0,a[i]); 112 ans+=getsum(block[x]+1,a[i]-1)-getsum(block[y],a[i]-1); 113 } 114 for(int i=L[block[y]];i<=y;i++){ 115 add(0,a[i],1); 116 ans+=getsum(0,n)-getsum(0,a[i]); 117 ans+=getsum(block[x]+1,n)-getsum(block[y],n)-(getsum(block[x]+1,a[i])-getsum(block[y],a[i])); 118 } 119 for(int i=x;i<=R[block[x]];i++){ 120 add(0,a[i],-1); 121 } 122 for(int i=L[block[y]];i<=y;i++){ 123 add(0,a[i],-1); 124 } 125 printf("%d\n",ans); 126 } 127 } 128 } 129 return 0; 130 }