分块预处理出[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; }