首先将作前缀和sum[i]=a[1]^a[2]^...^a[i],将询问变为max{sum[x-1]^sum[y]},l<=x<=y<=r。
假设我们要得到max{sum[x]^sum[y]},l<=y<=r的值,我们可以构建一颗Trie,存储sum[l],sum[l+1],...sum[r]的二进制串,然后再Trie上面贪心找最大值(能走不同就走不同,可以见USACO TRAING的Xor一题)。
显然不可能存储n^2个Trie,然后我们可以用和主席树一样的方法构建可持久化Trie。实际上,构建得到的可持久化Trie和sum[]数组的主席树是一模一样的!只是查询的时候有点不同而已。
但是对于本题的询问,x是可以变化的。我们可以分块,然后用f[i][j]表示x>=第x块的头,y<=j时的max{sum[x-1]^sum[y]}(在代码中稍有不同)。那么对于查询(l,r),设l属于块u,那么首先得到ans=f[u+1][r],然后枚举块u中的可行节点更新答案即可。
时间复杂度O((M+N)N^0.5logN)。
AC代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define N 13005
#define ll long long
using namespace std;
int n,m,trtot,ls[N<<5],rs[N<<5],sum[N<<5],rt[N];
int l[N],r[N],blg[N],f[115][N],a[N],bin[35];
void ins(int x,int &y,int k,int v){
y=++trtot; sum[y]=sum[x]+1;
if (k<0) return;
if (bin[k]&v){ ls[y]=ls[x]; ins(rs[x],rs[y],k-1,v); }
else{ rs[y]=rs[x]; ins(ls[x],ls[y],k-1,v); }
}
int qry(int x,int y,int z){
x=rt[x-1]; y=rt[y]; int k=30,ans=0;
for (; k>=0; k--){
int tmp=z&bin[k];
if (tmp)
if (sum[ls[y]]-sum[ls[x]]){ x=ls[x]; y=ls[y]; ans|=bin[k]; }
else{ x=rs[x]; y=rs[y]; }
else if (sum[rs[y]]-sum[rs[x]]){ x=rs[x]; y=rs[y]; ans|=bin[k]; }
else{ x=ls[x]; y=ls[y]; }
}
return ans;
}
int main(){
scanf("%d%d",&n,&m); int i,j;
bin[0]=1; for (i=1; i<=30; i++) bin[i]=bin[i-1]<<1;
a[1]=0; ins(rt[0],rt[1],30,0); n++;
for (i=2; i<=n; i++){
scanf("%d",&a[i]); a[i]^=a[i-1];
ins(rt[i-1],rt[i],30,a[i]);
}
int cnt=(int)sqrt((double)n);
for (i=1; i<=cnt; i++){
l[i]=r[i-1]+1; r[i]=r[i-1]+cnt;
}
r[cnt]=n;
for (i=1; i<=cnt; i++){
for (j=l[i]; j<=r[i]; j++) blg[j]=i;
for (j=l[i]; j<=n; j++)
f[i][j]=max(f[i][j-1],qry(l[i],j,a[j]));
}
int ans=0,x,y;
for (i=1; i<=m; i++){
scanf("%d%d",&x,&y);
x=((ll)x+ans)%(n-1)+1; y=((ll)y+ans)%(n-1)+1;
if (x>y) swap(x,y); y++;
ans=(blg[x]<blg[y])?f[blg[x]+1][y]:0;
for (j=x; j<=r[blg[x]] && j<=y; j++)
ans=max(ans,qry(x,y,a[j]));
printf("%d\n",ans); y--;
}
return 0;
}
by lych
2016.2.27