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
",last=ask(l,r));
  return 0;
}

  

原文地址:https://www.cnblogs.com/clrs97/p/4403206.html