L
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 ).
其中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
Sample Output
5
7
7
HINT
N=12000,M=6000,x,y,Ai在signed longint范围内。
Source
By seter
虽然每个题解都有写,但是
这题的x+lastans、y+lastans可能会在signed longint范围之外
因为咱一开始没有看见直到心血来潮点开讨论
思路:
因为区间很麻烦,所以考虑记录前缀异或和,问题变成在一段区间内,两两数之间的最大异或值。
对于这种最大异或值就要想到trie。
然后因为区间询问,所以trie需要可持久化。
那么得到一个
O(nm)
的暴力~
考虑优化:分块。
对于每个块,预处理块的起点到块起点后面的每个位置的询问答案。
对于每个询问,首先用最近的块左端点更新答案,然后剩下部分暴力
复杂度
O(n√m)
,可过~
这道题可以给人一个教训:当你实在改不出来时,记得看讨论……
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
inline int read()
{
int x=0;char ch=getchar();
while(ch<'0' || '9'<ch)ch=getchar();
while('0'<=ch && ch<='9')x=x*10+(ch^48),ch=getchar();
return x;
}
typedef long long ll;
const int N=12009;
const int M=N*45;
const int K=31;
int n,m,ans;
int a[N],s[N],sum[119][N];
int blk,bel[N],fst[N];
int rt[N],ch[M][2],val[M],tot;
inline void cp(int x,int y)
{
val[y]=val[x];
ch[y][0]=ch[x][0];
ch[y][1]=ch[x][1];
}
inline int insert(int pre,int dep,int x)
{
int now=++tot;
cp(pre,now);
val[now]++;
if(!dep)return now;
int nxt=(x>>(dep-1))&1;
ch[now][nxt]=insert(ch[pre][nxt],dep-1,x);
return now;
}
inline int query(int tl,int tr,int x)
{
int ret=0;
for(int i=K-1;i>=0;i--)
{
int nxt=(x>>i&1)^1;
if(val[ch[tr][nxt]]-val[ch[tl][nxt]]>0)
ret|=1<<i,tl=ch[tl][nxt],tr=ch[tr][nxt];
else
tl=ch[tl][nxt^1],tr=ch[tr][nxt^1];
}
return ret;
}
int main()
{
n=read(),m=read();
rt[0]=insert(0,K,s[0]);
for(int i=1;i<=n;i++)
rt[i]=insert(rt[i-1],K,s[i]=s[i-1]^(a[i]=read()));
blk=sqrt(n);
fst[bel[1]=0]=1;
for(int i=2;i<=n;i++)
{
bel[i]=i/blk;
if(bel[i]!=bel[i-1])
fst[bel[i]]=i;
}
for(int i=0;fst[i];i++)
for(int j=fst[i]+1;j<=n;j++)
sum[i][j]=max(sum[i][j-1],query(rt[fst[i]-1],rt[j-1],s[j]));
while(m--)
{
int l=((ll)read()+(ll)ans)%(ll)n+1;
int r=((ll)read()+(ll)ans)%(ll)n+1;
if(l>r)swap(l,r);
int p=l/blk+1;
ans=sum[p][r];
for(int i=min(p*blk-1,r-1);i>=l-1;i--)
ans=max(ans,query(rt[i],rt[r],s[i]));
printf("%d\n",ans);
}
return 0;
}