传送门
数据结构经典题。
首先考虑另外一种询问方式。
已知权值val,在区间
[
1
,
n
]
[1,n]
[1,n]中找一个数使得
v
a
l
val
val^
a
[
i
]
a[i]
a[i]最大。
这个可以直接01trie。
那么变成区间
[
l
,
r
]
[l,r]
[l,r]之后显然可以用可持久化01trie。
但是现在不知道权值val。
所以我们用分块预处理把时间复杂度变成
O
(
n
∗
s
q
r
t
(
n
)
∗
l
o
g
n
)
O(n*sqrt(n)*logn)
O(n∗sqrt(n)∗logn)的。
具体来说就是
m
x
[
i
]
[
j
]
mx[i][j]
mx[i][j]表示从第i块开头开始到j这段区间最大的两个数的异或和。
代码:
#include<bits/stdc++.h>
#define ll long long
#define N 12005
#define P 60
using namespace std;
inline ll read(){
ll ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
int n,m,sig,rt[N],blo[N];
ll lastans=0,mx[150][N],sum[N];
struct Trie{
int son[N*400][2],siz[N*400],tot;
inline int insert(ll val,int las){
int p,ret;
p=ret=++tot;
for(int i=P;~i;--i){
son[p][0]=son[las][0],son[p][1]=son[las][1],siz[p]=siz[las]+1;
ll tmp=(val>>i)&1ll;
son[p][tmp]=++tot,p=son[p][tmp],las=son[las][tmp];
}
siz[p]=siz[las]+1;
return ret;
}
inline ll query(int l,int r,ll val){
ll ret=0;
for(int i=P;~i;--i){
ll tmp=(val>>i)&1ll;
if(siz[son[r][tmp^1ll]]-siz[son[l][tmp^1ll]])ret|=1ll<<i,l=son[l][tmp^1ll],r=son[r][tmp^1ll];
else l=son[l][tmp],r=son[r][tmp];
}
return ret;
}
}T;
int main(){
n=read(),m=read(),sig=sqrt(n),T.tot=0;
for(int i=1;i<=n;++i)blo[i]=(i-1)/sig+1,rt[i]=T.insert((sum[i]=sum[i-1]^read()),rt[i-1]);
for(int i=1;i<=blo[n];++i){
ll tmp=0;
for(int j=(i-1)*sig+1;j<=n;++j)tmp=max(tmp,T.query(rt[(i-1)*sig-1],rt[j],sum[j])),mx[i][j]=tmp;
}
while(m--){
int l=(read()+lastans)%n+1,r=(read()+lastans)%n+1;
if(l>r)swap(l,r);
lastans=(blo[l]^blo[r])?mx[blo[l]+1][r]:0;
int ql=l-1,qr=min(r,blo[l]*sig);
for(int i=ql;i<=qr;++i)lastans=max(lastans,T.query(rt[l-2],rt[r],sum[i]));
printf("%lld\n",lastans);
}
return 0;
}