bzoj-3261 最大异或和

141 篇文章 0 订阅
88 篇文章 0 订阅
题意:

给出一个长度为n的初始序列,和m次操作;

A操作:在序列后面加入一个数;

Q操作:给出一段区间[l,r]和一个数x,求区间中的p使p的后缀异或和与x的异或值最大;

n,m<=300000;


题解:

可持久化数据结构(2/4)进行中... ...

先做一个转化,因为是在序列后面加数,维护后缀和并不容易;

但是由于异或性质可以转化成前缀和的问题;

也就是在区间中选一个数,使其与另一个数的异或值最大;

这显然是一个trie树的经典问题,但是这里涉及到了区间问题;

那么如果对每个区间搞棵trie树就解决了;

之后上可持久化就结束了,记录trie树上每个结点被经历的次数,以记录这个结点是否在区间内;

询问时下标似乎需要一点特判,处理的有点恶心了但是不太影响吧;

复杂度O(25(n+m));


代码:


#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 610000
using namespace std;
struct node
{
	int next[2],sum;
}a[N*30];
int root[N],tot;
char str[10];
void Insert(int x,int &p,int d)
{
	a[++tot]=a[p];
	p=tot;
	a[p].sum++;
	if(d==-1)	return ;
	Insert(x,a[p].next[(x&1<<d)?1:0],d-1);
}
int query(int nol,int nor,int x,int d)
{
	if(d==-1)	return 0;
	bool index=x&(1<<d)?1:0;
	if(a[a[nor].next[!index]].sum>a[a[nol].next[!index]].sum)
		return 1<<d|query(a[nol].next[!index],a[nor].next[!index],x,d-1);
	else
		return query(a[nol].next[index],a[nor].next[index],x,d-1);
}
int main()
{
	int n,m,i,j,k,l,r,x,all;
	scanf("%d%d",&n,&m);
	for(i=1,all=0;i<=n;i++)
	{
		scanf("%d",&x);
 		all^=x;
		root[i]=root[i-1];
		Insert(all,root[i],25);
	}
	for(i=1;i<=m;i++)
	{
		scanf("%s",str);
		if(str[0]=='A')
		{
			scanf("%d",&x);
			all^=x;
			root[n+1]=root[n];
			Insert(all,root[++n],25);
		}
		else
		{
			scanf("%d%d%d",&l,&r,&x);
			x=x^all;
			if(r==1)
			printf("%d\n",x);
			else if(l==1)
			printf("%d\n",max(x,query(root[0],root[r-1],x,25)));
			else
			printf("%d\n",query(root[l-2],root[r-1],x,25));
		}
	}
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值