首先很显然维护异或前缀和让询问区间连续一段变成询问两个单点.
然后就比较套路了,发现每一次都是询问一个区间内而且不满足我们已知知识内的一些特殊性质例如单调性,但是暴力又可以很容易的做出来,所以这个时候就可以考虑分块了设f[i][j] 表示第i块开始到j的最大异或值,然后就很简单了
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#define LL long long
#define maxn 20021
using namespace std;
int f[400][maxn],a[maxn],sum[maxn*40],ch[maxn*40][2],rt[maxn];
int tot,n,m,block,bl[maxn],num;
void insert(int x,int& y,int val){
int root;root=y=++tot,sum[y]=sum[x]+1;
for(int c,i=30;i>=0;i--){
c=(val>>i)&1;
ch[root][!c]=ch[x][!c];
root=ch[root][c]=++tot;
x=ch[x][c];
sum[root]=sum[x]+1;
}
}
int query(int a,int b,int val){
a=rt[a-1],b=rt[b];
int ans=0;
for(int c,i=30;i>=0;i--){
c=(val>>i)&1;
if(sum[ch[b][!c]]-sum[ch[a][!c]])
ans=ans<<1|1,b=ch[b][!c],a=ch[a][!c];
else ans=ans<<1,a=ch[a][c],b=ch[b][c];
}return ans;
}
void solve(){
LL l,r,x,y;int ans=0;
while(m--){
scanf("%lld%lld",&x,&y);
l=(x+ans)%n+1,r=(y+ans)%n+1;
if(l>r)swap(l,r);
l--,ans=0;
if(bl[l]==bl[r]){
for(int i=l;i<=r;i++)ans=max(ans,query(l,r,a[i]));
printf("%d\n",ans);
}else{
int t=bl[l]*block;
ans=f[bl[l]+1][r];
for(int i=l;i<=t;i++)ans=max(ans,query(l,r,a[i]));
printf("%d\n",ans);
}
}
}
int main(){
scanf("%d%d",&n,&m);block=sqrt(n);
num=n/block+(n%block!=0);
insert(rt[0],rt[0],0);
for(int i=1;i<=n;i++){
scanf("%d",a+i),a[i]^=a[i-1];
insert(rt[i-1],rt[i],a[i]);
bl[i]=(i-1)/block+1;
}
for(int s,i=1;i<=num;i++){
s=(i-1)*block+1;
for(int j=s;j<=n;j++){
f[i][j]=max(f[i][j-1],query(s,j,a[j]));
}
}
solve();
return 0;
}