2741: 【FOTILE模拟赛】L
Time Limit: 15 Sec
Memory Limit: 162 MB
Submit: 2032
Solved: 559
[ Submit][ Status][ Discuss]
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
Sample Input
3 3
1 4 3
0 1
0 1
4 3
Sample Output
5
7
7
HINT
HINT
N=12000,M=6000,x,y,Ai在signed longint范围内。
Source
分块+可持久化Trie树
分块的思路很棒!!!
看到连续异或和,很容易想到预处理出异或的前缀和s[i],然后将区间[l,r]的异或和转化为s[l-1]^s[r]。于是每个询问就转化为在s[l-1]到s[r]之间找两个数,使其异或值最大。
我们先考虑问题的简化版:在区间内找一个数,使它与另一个已知数的异或值最大。这个问题可以用可持久化Trie树解决,只需要在Trie树上走相异的节点。
那这个问题要如何解决呢?
我们先把区间分块,再预处理出f[i][j],表示从第i块的起始点到第j个点之间两个数异或的最大值。这可以采用递推:f[i][j]=max(f[i-1][j-1],query((i-1)*block+1,j,a[j]))。
然后对于每个询问,找到区间内第一个完整块的起始点x,答案赋值为f[pos[x]][r],然后对于左边剩余的点暴力计算并和答案取max。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define maxn 20000
#define maxm 800000
using namespace std;
int n,m,tot,block,num;
int a[maxn],rt[maxn],pos[maxn],id[maxm],t[maxm][2],f[400][maxn];
inline int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void insert(int pre,int k,int x)
{
int now=rt[k]=++tot;id[tot]=k;
pre=rt[pre];
D(i,30,0)
{
int j=(x>>i)&1;
t[now][j^1]=t[pre][j^1];
t[now][j]=++tot;id[tot]=k;
now=t[now][j];pre=t[pre][j];
}
}
inline int query(int l,int r,int x)
{
int ans=0,tmp=rt[r];
D(i,30,0)
{
if (id[tmp]<l) break;
int j=((x>>i)&1)^1;
if (id[t[tmp][j]]>=l) ans|=(1<<i);
else j^=1;
tmp=t[tmp][j];
}
return ans;
}
int main()
{
n=read();m=read();
block=int(sqrt(n));num=n/block+(n%block!=0);
F(i,1,n) pos[i]=(i-1)/block+1;
id[0]=-1;insert(0,0,0);
F(i,1,n) a[i]=a[i-1]^read();
F(i,1,n) insert(i-1,i,a[i]);
F(i,1,num) F(j,(i-1)*block+1,n)
f[i][j]=max(f[i][j-1],query((i-1)*block+1,j,a[j]));
int ans=0;
while (m--)
{
ll l,r,x=read(),y=read();
l=((ll)ans+x)%n+1;r=((ll)ans+y)%n+1;
if (l>r) swap(l,r);
ans=0;l--;
if (pos[l]==pos[r])
{
F(i,l,r) ans=max(ans,query(l,r,a[i]));
}
else
{
ans=f[pos[l]+1][r];
F(i,l,pos[l]*block) ans=max(ans,query(l,r,a[i]));
}
printf("%d\n",ans);
}
return 0;
}