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 }

 

posted @ 2018-08-19 09:14  Xu-daxia  阅读(242)  评论(0编辑  收藏  举报