[BZOJ3261]最大异或和

Posted by Dispwnl on February 16, 2019

题目

Description

给定一个非负整数序列{a},初始长度为N。

有M个操作,有以下两种操作类型:

1、Ax:添加操作,表示在序列末尾添加一个数x,序列的长度N+1。

2、Qlrx:询问操作,你需要找到一个位置p,满足l<=p<=r,使得:

a[p] xor a[p+1] xor … xor a[N] xor x 最大,输出最大是多少。

Input

第一行包含两个整数 N ,M,含义如问题描述所示。
第二行包含 N个非负整数,表示初始的序列 A 。 接下来 M行,每行描述一个操作,格式如题面所述。

Output

假设询问操作有 T个,则输出应该有 T行,每行一个整数表示询问的答案。

Sample Input

5 5
2 6 4 3 6
A 1 
Q 3 5 4 
A 4 
Q 5 7 0 
Q 3 6 6 

Sample Output

4 
5
6 

HINT

对于测试点 1-2,N,M<=5 。 对于测试点 3-7,N,M<=80000 。 对于测试点 8-10,N,M<=300000 。 其中测试点 1, 3, 5, 7, 9保证没有修改操作。 0<=a[i]<=10^7。

题解

把操作离线下来,相当于一个一个在后面删数,往可持久化$Trie$中插后缀异或和

记录序列现在的长度$N$,每次查询就是询问和$x\oplus s_{N+1}$异或的最大值

代码

# include<iostream>
# include<cstring>
# include<cstdio>
# include<algorithm>
using namespace std;
const int MAX=6e5+5,N=2e7+5;
struct p{
	int x,l,r;
	bool fl;
}qu[MAX];
int N_,n,m,tot;
struct Trie{
	int siz[N];
	int son[N][2];
	void ins(int &k,int pre,int x,int o=24)
	{
		k=++tot,son[k][0]=son[pre][0],son[k][1]=son[pre][1],siz[k]=siz[pre]+1;
		if(o==-1) return;
		if(x&(1<<o)) ins(son[k][1],son[pre][1],x,o-1);
		else ins(son[k][0],son[pre][0],x,o-1);
	}
	int ask(int L,int R,int x,int o=24)
	{
		if(o==-1) return 0;
		int v=bool(x&(1<<o))^1,tt=siz[son[R][v]]-siz[son[L][v]];
		if(tt) return ask(son[L][v],son[R][v],x,o-1)+(1<<o);
		return ask(son[L][v^1],son[R][v^1],x,o-1);
	}
}Tree;
int xsum[MAX],a[MAX],rt[MAX],ans[MAX];
char A[5];
int read()
{
	int x(0);
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar());
	for(;isdigit(ch);x=x*10+ch-48,ch=getchar());
	return x;
}
int main()
{
	N_=n=read(),m=read();
	for(int i=1;i<=n;++i)
	  a[i]=read();
	for(int i=1;i<=m;++i)
	  {
	  	scanf("%s",A);
	  	if(A[0]=='A') a[++N_]=qu[i].x=read();
	  	else if(A[0]=='Q') qu[i].fl=1,qu[i].l=read(),qu[i].r=read(),qu[i].x=read();
	  }
	for(int i=N_;i>=1;--i)
	  xsum[i]=xsum[i+1]^a[i];
	for(int i=1;i<=N_;++i)
	  Tree.ins(rt[i],rt[i-1],xsum[i]);
	for(int i=m,_N=N_+1;i>=1;--i)
	  if(!qu[i].fl) --_N;
	  else if(qu[i].fl) ans[i]=Tree.ask(rt[qu[i].l-1],rt[qu[i].r],qu[i].x^xsum[_N]);
	for(int i=1;i<=m;++i)
	  if(qu[i].fl) printf("%d\n",ans[i]);
	return 0;
}