题意:
给出一个长度为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;
}