给出一个长度为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; }
原文地址:http://blog.csdn.net/ww140142/article/details/47057431