zoukankan      html  css  js  c++  java
  • 【分块】【树状数组】bzoj3744 Gty的妹子序列

    离散化,分块。

    预处理出:ans[i][j] 第i块到第j块的逆序对数。

    f[i][j] 第1~i块中大于j的数的个数。

    g[i][j] 第1~j块中小于j的数的个数。

    每次询问时对于整块部分可以O(1)获得。

    对于零散部分呢?

    >在一列数的后面添加一个数,逆序对数会增加 数列中比它大的数的个数。

    >在一列数的前面添加一个数,逆序对数会增加 数列中比它小的数的个数。

    所以统计以上信息的时候,对于整块的部分,我们可以借由预处理的东西差分来O(1)地获得答案,零散的部分就是树状数组咯。

    空间复杂度是O(n*sqrt(n))的。

    时间复杂度是O(n*sqrt(n)*log(n))的。

    P.S.根本不用卡常数什么的呢。

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<cstring>
      4 #include<cmath>
      5 using namespace std;
      6 #define N 50001
      7 #define BLOCK_SIZE 250
      8 int sz,sum,n,a[N],l[BLOCK_SIZE],r[BLOCK_SIZE],D[N],f[BLOCK_SIZE][BLOCK_SIZE];
      9 int Less[BLOCK_SIZE][N],More[BLOCK_SIZE][N],b[N],en,m,x,y,num[N],ans;
     10 struct Point{int v,p;}t[N];
     11 bool operator < (const Point &a,const Point &b){return a.v<b.v;}
     12 int Res,Num;char C,CH[12];
     13 inline int G()
     14 {
     15     Res=0;C='*';
     16     while(C<'0'||C>'9')C=getchar();
     17     while(C>='0'&&C<='9'){Res=Res*10+(C-'0');C=getchar();}
     18     return Res;
     19 }
     20 inline void P(int x)
     21 {
     22     Num=0;if(!x){putchar('0');puts("");return;}
     23     while(x>0)CH[++Num]=x%10,x/=10;
     24     while(Num)putchar(CH[Num--]+48);
     25     puts("");
     26 }
     27 void add(int p,const int &v) {while(p<=n) {D[p]+=v; p+=(p&(-p));}}
     28 int getsum(int p) {int res=0; while(p) {res+=D[p]; p-=(p&(-p));} return res;}
     29 void makeblock()
     30 {
     31     sz=sqrt(n); if(!sz) sz=1;
     32     for(sum=1;sum*sz<n;sum++)
     33       {
     34           l[sum]=r[sum-1]+1;
     35           r[sum]=sum*sz;
     36           for(int i=l[sum];i<=r[sum];i++) num[i]=sum;
     37       }
     38     l[sum]=r[sum-1]+1;
     39     r[sum]=n;
     40     for(int i=l[sum];i<=r[sum];i++) num[i]=sum;
     41 }
     42 void LiSan()
     43 {
     44     sort(t+1,t+n+1); a[t[1].p]=++en;
     45     for(int i=2;i<=n;i++)
     46       {
     47           if(t[i].v!=t[i-1].v) en++;
     48           a[t[i].p]=en;
     49       }
     50 }
     51 void init_each_ans()
     52 {
     53     for(int i=1;i<=sum;i++)
     54       {
     55           memset(D,0,sizeof(D)); int pos=0,res=0;
     56           for(int j=i;j<=sum;j++)
     57             {
     58                 for(int k=l[j];k<=r[j];k++)
     59                   {
     60                       pos++;
     61                       add(a[k],1);
     62                       res+=(pos-getsum(a[k]));
     63                   }
     64                 f[i][j]=res;
     65             }
     66       } memset(D,0,sizeof(D));
     67 }
     68 void init_sum()
     69 {
     70     memcpy(b,a,sizeof(b));
     71     for(int i=1;i<=sum;i++)
     72       {
     73         sort(b+l[i],b+r[i]+1);
     74           memcpy(More[i],More[i-1],sizeof(More[i]));
     75           memcpy(Less[i],Less[i-1],sizeof(Less[i]));
     76           for(int j=1;j<=en;j++)
     77             {
     78                 More[i][j]+=(b+r[i]+1-upper_bound(b+l[i],b+r[i]+1,j));
     79                 Less[i][j]+=(lower_bound(b+l[i],b+r[i]+1,j)-(b+l[i]));
     80             }
     81       }
     82 }
     83 int getMore(const int &L,const int &R,const int &v){return More[R][v]-More[L-1][v];}
     84 int getLess(const int &L,const int &R,const int &v){return Less[R][v]-Less[L-1][v];}
     85 int main()
     86 {
     87     n=G();
     88     for(int i=1;i<=n;i++)
     89       {
     90           t[i].v=G();
     91           t[i].p=i;
     92       }
     93     LiSan(); makeblock(); init_each_ans(); init_sum();
     94     m=G();
     95     for(int j=1;j<=m;j++)
     96       {
     97           x=G(); y=G(); x^=ans; y^=ans;
     98           if(num[x]+1>=num[y])
     99             {
    100                 int pos=0; ans=0;
    101                 for(int i=x;i<=y;i++)
    102                   {
    103                       pos++;
    104                       add(a[i],1);
    105                       ans+=(pos-getsum(a[i]));
    106                   }
    107                 for(int i=x;i<=y;i++) add(a[i],-1);
    108               P(ans);
    109             }
    110           else
    111             {
    112                 int pos=r[num[x]]-x+1; ans=f[num[x]+1][num[y]-1];
    113                 for(int i=r[num[x]];i>=x;i--)
    114                   {
    115                       ans+=(getLess(num[x]+1,num[y]-1,a[i])+getsum(a[i]-1));
    116                       add(a[i],1);
    117                   }
    118                 for(int i=l[num[y]];i<=y;i++)
    119                   {
    120                       pos++;
    121                       add(a[i],1);
    122                       ans+=(pos-getsum(a[i])+getMore(num[x]+1,num[y]-1,a[i]));
    123                   }
    124                 for(int i=x;i<=r[num[x]];i++) add(a[i],-1);
    125                 for(int i=l[num[y]];i<=y;i++) add(a[i],-1);
    126               P(ans);
    127             }
    128       }
    129     return 0;
    130 }
  • 相关阅读:
    797. 所有可能的路径
    1286. 字母组合迭代器
    216. 组合总和 III
    77. 组合
    784. 字母大小写全排列
    90. 子集 II
    78. 子集
    47. 全排列 II
    46. 全排列
    40. 组合总和 II
  • 原文地址:https://www.cnblogs.com/autsky-jadek/p/4101591.html
Copyright © 2011-2022 走看看