【GDOI2018模拟9.21】数列
程序员文章站
2022-06-23 10:49:34
...
(File IO): input:sequence.in output:sequence.out
Time Limits: 2000 ms Memory Limits: 262144 KB Detailed Limits
Description
Input
Output
Sample Input
5 5 0
3 1 2 9 4
1 5
4 4
1 4
1 3
2 5
Sample Output
3
4
15
11
3
Data Constraint
题解
首先这样的二进制题目一般都是用trie来解决的
设sum[i][j]=ai xor xi+1… xor xj
有sum[i][j]=sum[i][k] xor sum[k+1][j]
那么我们可以构一个可持久化trie,把前缀和都挂上去,那么每次询问就可以做到n log 级别
考虑分块
我们可以与处理一个an[x][y]表示
那么在算答案的时候我们只需要计算两端中至少有一个不在括住的完整的块里面的最大值了,复杂度
贴代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fo1(i,b,a) for(i=b;i>=a;i--)
const int maxn=2e5+5,bl=155;
using namespace std;
int a[maxn],root[maxn],bb[maxn],ee[maxn],cc[30],sum[maxn];
int g[maxn][bl];
int be[bl],ed[bl],an[bl][bl];
int go[maxn*40][3];
int i,j,k,l,m,n,q,x,y,z,now,qu,tot,t1,t2,p,ans,t,r,ss;
bool bz;
void ge(int x,int y){
int j;
tot=0;
fo1(j,29,0){
if ((z & cc[j])>0) p=1; else p=0; p=p xor 1;
if (go[go[x][p]][2]-go[go[y][p]][2]!=0){
x=go[x][p]; y=go[y][p]; tot=tot+cc[j];
} else{
p=p xor 1;
x=go[x][p]; y=go[y][p];
}
}
if (bz) tot=max(tot,z);
}
int main(){
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
scanf("%d%d%d",&n,&q,&t);
cc[0]=1;
fo(i,1,30) cc[i]=cc[i-1]*2;
fo(i,1,n){
scanf("%d",&a[i]);
x=x xor a[i];
sum[i]=x;
root[i]=++now;
y=root[i-1];
z=root[i]; go[z][2]=i;
fo1(j,29,0){
if ((x & cc[j])>0){
go[z][0]=go[y][0]; go[z][1]=++now; z=now; go[now][2]=go[go[y][1]][2]+1;
y=go[y][1];
} else{
go[z][1]=go[y][1]; go[z][0]=++now; z=now; go[now][2]=go[go[y][0]][2]+1;
y=go[y][0];
}
}
}
x=trunc(sqrt(n))-1;
be[1]=1; ed[1]=1+x; y=1; z=1+x; bb[1]=1; ee[1+x]=1;
while (z<=n){
if (z+x>=n){
be[y+1]=ed[y]+1;
ed[y+1]=n; y++; bb[be[y]]=y; ee[ed[y]]=y; break;
}
be[y+1]=ed[y]+1; y++;
ed[y]=be[y]+x;
bb[be[y]]=y; ee[ed[y]]=y;
z=ed[y];
}
qu=y;
fo(i,1,qu){
ans=0;
fo1(j,i,1){
fo(k,be[i],ed[i]){
bz=false;
y=root[k]; x=root[be[j]-1]; z=sum[k];
if (be[j]>=2) x=root[be[j]-2]; else bz=true;
ge(x,y);
ans=max(ans,tot);
}
an[i][j]=ans;
}
}
ans=0;
fo(i,1,q){
scanf("%d%d",&x,&y);
x=(x+t*ans)%n+1;
y=(y+t*ans)%n+1;
l=min(x,y);
r=max(x,y);
x=l; y=r;
while (y && ee[y]==0) y--;
while (x<=n && bb[x]==0) x++;
t1=bb[x]; t2=ee[y];
ans=0;
if (x>0 && y>0)
while (t2>=t1){
ans=max(ans,an[t2][t1]);
t2--;
}
y=max(y,l);
x=min(x,r);
fo(j,y,r){
z=sum[j];
bz=false;
ss=max(0,l-2); if (l==1) bz=true;
ge(root[ss],root[j]);
ans=max(ans,tot);
}
fo(j,l,x){
bz=false;
z=sum[j-1];
ge(root[j-1],root[r]);
ans=max(ans,tot);
}
printf("%d\n",ans);
}
return 0;
}