Description
FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和。
即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor Aj),其中l<=i<=j<=r。
为了体现在线操作,对于一个询问(x,y):
l = min ( ((x+lastans) mod N)+1 , ((y+lastans) mod N)+1 ).
r = max ( ((x+lastans) mod N)+1 , ((y+lastans) mod N)+1 ).
r = max ( ((x+lastans) mod N)+1 , ((y+lastans) mod N)+1 ).
其中lastans是上次询问的答案,一开始为0。
Input
第一行两个整数N和M。
第二行有N个正整数,其中第i个数为Ai,有多余空格。
后M行每行两个数x,y表示一对询问。
Output
共M行,第i行一个正整数表示第i个询问的结果。
Sample Input
3 3
1 4 3
0 1
0 1
4 3
1 4 3
0 1
0 1
4 3
Sample Output
5
7
7
7
7
HINT
HINT
N=12000,M=6000,x,y,Ai在signed longint范围内。
分块+可持久化trie
用f[i][j]表示第i块开头到位置j的最大ans
f[i][j]=max(f[i][j-1],ask(head[i],j-1,a[j]))
这里处理是nsqrt(n)logn
然后每次询问的时候把整块的一起处理
再枚举前面部分的位置,更新ans即可
#include<cmath>
#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
struct tree
{
int l,r;
int ll,rr;
}tr[5000001];
int root[600001];
long long px[32];
int tot;
inline int add(int p,int d,int dep)
{
if(dep==31)
return 0;
if(d>=px[dep])
{
tot++;
int pp=tot;
tr[pp].l=tr[p].l;
tr[pp].ll=tr[p].ll;
tr[pp].r=add(tr[p].r,d-px[dep],dep+1);
tr[pp].rr=tr[p].rr+1;
return pp;
}
else
{
tot++;
int pp=tot;
tr[pp].l=add(tr[p].l,d,dep+1);
tr[pp].ll=tr[p].ll+1;
tr[pp].r=tr[p].r;
tr[pp].rr=tr[p].rr;
return pp;
}
}
inline int ask(int l,int r,int x,int dep)
{
if(dep==31)
return 0;
if(x>=px[dep])
{
if(tr[r].ll-tr[l].ll>0)
return px[dep]+ask(tr[l].l,tr[r].l,x-px[dep],dep+1);
else
return ask(tr[l].r,tr[r].r,x-px[dep],dep+1);
}
else
{
if(tr[r].rr-tr[l].rr>0)
return px[dep]+ask(tr[l].r,tr[r].r,x,dep+1);
else
return ask(tr[l].l,tr[r].l,x,dep+1);
}
}
int a[100001];
int x[100001];
int belong[100001];
int head[1001];
int f[1001][20001];
int main()
{
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
long long n;
int m;
scanf("%lld%d",&n,&m);
int i,j;
px[0]=1;
for(i=1;i<=30;i++)
px[i]=px[i-1]*2;
for(i=0;i<=15;i++)
{
int t=px[i];
px[i]=px[30-i];
px[30-i]=t;
}
root[0]=1;
add(0,0,0);
for(i=1;i<=n;i++)
{
scanf("%lld",&x[i]);
a[i]=(a[i-1]^x[i]);
root[i]=tot+1;
add(root[i-1],a[i],0);
}
int nt=sqrt(n);
int nx=0;
for(i=1;i<=n;i++)
{
belong[i]=(i-1)/nt+1;
if(belong[i]!=belong[i-1])
{
nx++;
head[belong[i]]=i;
}
}
head[nx+1]=n+1;
for(i=1;i<=nx;i++)
{
f[i][head[i]]=x[head[i]];
for(j=head[i]+1;j<=n;j++)
{
int rt=head[i]-2;
if(rt<0)
rt=0;
else
rt=root[rt];
f[i][j]=max(f[i][j-1],ask(rt,root[j-1],a[j],0));
}
}
long long s,t;
long long last=0;
for(i=1;i<=m;i++)
{
scanf("%lld%lld",&s,&t);
int ss=(s+last)%n+(long long)1,tt=(t+last)%n+(long long)1;
s=min(ss,tt);
t=max(ss,tt);
/* if(s==t)
{
printf("%d\n",x[s]);
continue;
}*/
int nxt=belong[s];
if(head[nxt]!=s)
nxt++;
int ans=f[nxt][t];
for(j=s;j<=min(head[nxt]-1,(int)t);j++)
{
ans=max(ans,ask(root[s-1],root[t],a[j-1],0));
}
printf("%lld\n",ans);
last=ans;
}
return 0;
}