bzoj3261 最大异或和

3261: 最大异或和

Time Limit: 10 Sec   Memory Limit: 512 MB
Submit: 1114   Solved: 472
[ Submit][ Status][ Discuss]

Description

     

给定一个非负整数序列 {a},初始长度为 N。       
有   M个操作,有以下两种操作类型:
 
1 、A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1。
2 、Q l r x:询问操作,你需要找到一个位置 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
对于测试点 1-2,N,M<=5 。

对于测试点 3-7,N,M<=80000 。
对于测试点 8-10,N,M<=300000 。

其中测试点 1, 3, 5, 7, 9保证没有修改操作。
对于 100% 的数据, 0<=a[i]<=10^7。

Sample Output

4
5
6

HINT

对于      100%  的数据,     0<=a[i]<=10^7  

Source




可持久化Trie树第一题。

首先我们可以维护前缀异或和(这里充分利用了异或的性质),然后就是求x^sum[n]^sum[p-1]的最大值。又因为x^sum[n]是定值,所以在Trie树上贪心即可。

考虑到p是在区间[l-1,r-1]内的,所以我们不能对于每次询问建一个Trie树。但是我们可以对于Trie树维护前缀和,建立可持久化Trie树。这样每次询问,只要在trie[r-1]-trie[l-1]上贪心就可以了。

还有两点需要注意的:

  1.一开始要插入一个数0,因为最初异或和等于0。

  2.对于每个点要维护一个id,这样便于询问操作中判断该节点是否在区间[l-1,r-1]内。特别地,id[0]=1,这保证了空节点不会被访问。(详见代码)




#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#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 600005
#define maxm 20000005
using namespace std;
int n,m,tot=0,sum=0;
int rt[maxn],id[maxm],t[maxm][2];
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 x,int k)
{
	int now=rt[k]=++tot;id[tot]=k;
	D(i,24,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,24,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();
	id[0]=-1;
	insert(0,0,0);
	F(i,1,n)
	{
		sum^=read();
		insert(rt[i-1],sum,i);
	}
	F(i,1,m)
	{
		char ch=getchar();
		while (ch<'A'||ch>'Z') ch=getchar();
		if (ch=='A')
		{
			sum^=read();
			insert(rt[n],sum,n+1);
			n++;
		}
		else
		{
			int l=read(),r=read(),x=read();
			printf("%d\n",query(l-1,r-1,sum^x));
		}
	}
	return 0;
}


你可能感兴趣的:(bzoj,可持久化Trie树)