zoukankan      html  css  js  c++  java
  • 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(nsqrt{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
    ",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
    ",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 }
  • 相关阅读:
    素数个数(素数➕dfs)
    最小正子段和
    set<int> 的用法
    C
    map的用法
    B
    威佐夫博弈
    Stars(树状数组)
    upper_bound和lower_bound的用法
    超级大水题(还是自己过不了的水题)
  • 原文地址:https://www.cnblogs.com/Menhera/p/9558254.html
Copyright © 2011-2022 走看看