BZOJ3744 : Gty的妹子序列

分块预处理出[i,j]块内的答案以及数字出现次数,查询时向两边转移,用树状数组维护,复杂度$O((n+m)\sqrt{n}\log n)$。

 

#include<cstdio>

#include<algorithm>

const int N=50010,K=226;

int n,m,l,r,i,j,k,size,block,a[N],b[N],pos[N],st[K],en[K],ans[K][K],ap[K][N],T,now,all,bit[N],vis[N],last;

inline void read(int&a){char ch;while(!(((ch=getchar())>='0')&&(ch<='9')));a=ch-'0';while(((ch=getchar())>='0')&&(ch<='9'))(a*=10)+=ch-'0';}

inline int lower(int x){

  int l=1,r=n,mid,t;

  while(l<=r)if(b[mid=(l+r)>>1]<=x)l=(t=mid)+1;else r=mid-1;

  return t;

}

inline void add(int x){for(;x<=n;x+=x&-x)if(vis[x]!=T)vis[x]=T,bit[x]=1;else bit[x]++;}

inline int sum(int x){int t=0;for(;x;x-=x&-x)if(vis[x]==T)t+=bit[x];return t;}

inline int ask(int l,int r){

  T++;

  if(pos[l]==pos[r]){

    now=0;

    for(;r>=l;r--)now+=sum(a[r]-1),add(a[r]);

    return now;

  }

  now=ans[pos[l]+1][pos[r]-1],all=st[pos[r]]-en[pos[l]]-1;

  for(i=en[pos[l]];i>=l;i--)now+=sum(a[i]-1)+ap[pos[r]-1][a[i]-1]-ap[pos[l]][a[i]-1],add(a[i]),all++;

  for(i=st[pos[r]];i<=r;i++)now+=all-sum(a[i])-ap[pos[r]-1][a[i]]+ap[pos[l]][a[i]],add(a[i]),all++;

  return now;

}

int main(){

  read(n);

  for(i=1;i<=n;i++)read(a[i]),b[i]=a[i];

  for(std::sort(b+1,b+n+1),i=1;i<=n;i++)a[i]=lower(a[i]);

  for(;size*size<n;size++);

  for(i=1;i<=n;i++)pos[i]=(i-1)/size+1;

  for(block=pos[n],i=1;i<=block;i++)st[i]=size*(i-1)+1;

  for(en[block]=n,i=block-1;i;i--)en[i]=st[i+1]-1;

  for(i=1;i<=block;i++){

    now=all=0,T++;

    for(j=1;j<=n;j++)ap[i][j]=ap[i-1][j];

    for(j=i;j<=block;ans[i][j++]=now)for(k=st[j];k<=en[j];k++)now+=all-sum(a[k]),add(a[k]),all++,ap[j][a[k]]++;

  }

  for(i=1;i<=block;i++)for(j=2;j<=n;j++)ap[i][j]+=ap[i][j-1];

  read(m);

  while(m--)read(l),read(r),l^=last,r^=last,printf("%d\n",last=ask(l,r));

  return 0;

}

  

 

你可能感兴趣的:(ZOJ)