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范围内。
分析:
第一步显然是跑出前缀异或和了,这样一个询问
[l,r]
[
l
,
r
]
可以看做查询
[l−1,r]
[
l
−
1
,
r
]
的任意两个数的异或和。然后我们对区间分块,设
f[i][j]
f
[
i
]
[
j
]
表示第
i
i
个块左端点到第个位置的这段区间的答案。
那么
其中 l[i] l [ i ] 为第 i i 个块左端点,表示查询 k k 在区间内最大值(就是确定一个数是 k k )。
对于查询,我们可以知道 x x 的下一个块的左端点到的答案。至于 x x 到下一个左端点的些数,我们可以暴力查询就可以了。
一开始跑爆int,开了long long就T了。
代码:
/**************************************************************
Problem: 2741
User: liangzihao
Language: C++
Result: Accepted
Time:11380 ms
Memory:29592 kb
****************************************************************/
#include <iostream>
#include <cmath>
#include <cstdio>
#define LL long long
const int maxn=2e4+7;
const int maxp=31;
using namespace std;
int a[maxn],f[207][maxn],bit[maxn],l[maxn];
int n,m,cnt,block,lastans,x,y;
int root[maxn],belong[maxn];
struct node{
int l,r;
int sum;
}t[maxn*50];
void ins(int &p,int q,int d,int k)
{
if (!p) p=++cnt;
t[p].sum=t[q].sum+1;
if (d<0) return;
if (bit[d]&k) t[p].l=t[q].l,ins(t[p].r,t[q].r,d-1,k);
else t[p].r=t[q].r,ins(t[p].l,t[q].l,d-1,k);
}
int getmax(int p,int q,int d,int k)
{
if (d<0) return 0;
int suml=t[t[p].l].sum-t[t[q].l].sum;
int sumr=t[t[p].r].sum-t[t[q].r].sum;
if (bit[d]&k)
{
if (suml) return getmax(t[p].l,t[q].l,d-1,k);
else return getmax(t[p].r,t[q].r,d-1,k)+bit[d];
}
else
{
if (sumr) return getmax(t[p].r,t[q].r,d-1,k)+bit[d];
else return getmax(t[p].l,t[q].l,d-1,k);
}
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=n;i++) a[i]^=a[i-1];
bit[0]=1;
for (int i=1;i<=maxp;i++) bit[i]=bit[i-1]*2;
for (int i=1;i<=n;i++) ins(root[i],root[i-1],maxp,a[i]);
block=trunc(sqrt(n));
int sum=n/block+(n%block!=0);
for (int i=1;i<=sum;i++) l[i]=(i-1)*block+1;
l[sum+1]=n+1;
for (int i=1;i<=n;i++) belong[i]=(i-1)/block+1;
for (int i=1;i<=sum;i++)
{
for (int j=l[i];j<=n;j++)
{
int ret=getmax(root[j],root[l[i]-1],maxp,a[j]);
f[i][j]=max(f[i][j-1],ret^a[j]);
}
}
lastans=0;
for (int i=1;i<=m;i++)
{
LL xx,yy;
scanf("%lld%lld",&xx,&yy);
x=min(((xx+(LL)lastans)%n)+1,((yy+(LL)lastans)%n)+1);
y=max(((xx+(LL)lastans)%n)+1,((yy+(LL)lastans)%n)+1);
lastans=0;
if (x==1) lastans=getmax(root[y],root[0],maxp,0);
else x--;
int d=belong[x];
if (x==l[d]) lastans=max(lastans,f[d][y]);
else
{
if (l[d+1]<=y) lastans=f[d+1][y];
for (int j=x;j<=min(l[d+1]-1,y);j++)
lastans=max(lastans,getmax(root[y],root[j],maxp,a[j])^a[j]);
}
printf("%d\n",lastans);
}
}