bzoj3261: 最大异或和
3261: 最大异或和
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1369 Solved: 578
[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行,每行一个整数表示询问的答案。
可持久化trie模版题....
--------
hzwer:
View Code
记b[i]为1到i的a的异或和
则求max(b[p]^b[n]^x) (l-1<=p<=r-1)
每次加点将trie树的这条链的权都+1
修改当然是新建一个结点(类可持久化线段树)
然后查询的时候判断一个结点存在,只要做区间减法判权是否非0
即若sum[r]-sum[l-1]=0则该结点不存在
查询的贪心策略略。。。
实现的时候数列开始加入一个数0会比较好处理
---------
1 #include<bits/stdc++.h> 2 #define rep(i,l,r) for(int i=l;i<=r;++i) 3 using namespace std; 4 const int N=15023333; 5 int n,m,a[N],two[30],l,r,x,rt[N],b[N],ch[N][2],cnt,sum[N]; 6 char c[50]; 7 int add(int x,int val){ 8 int tmp,y=tmp=++cnt,t; 9 for(int i=23;i>=0;--i){ 10 ch[y][0]=ch[x][0]; ch[y][1]=ch[x][1]; 11 sum[y]=sum[x]+1; 12 t=val&two[i]; t>>=i; 13 x=ch[x][t]; 14 y=ch[y][t]=++cnt; 15 } 16 sum[y]=sum[x]+1; 17 return tmp; 18 } 19 inline int que(int l,int r,int val){ 20 int tmp=0,t; 21 for(int i=23;i>=0;i--){ 22 t=val&two[i]; t>>=i; 23 if(sum[ch[r][t^1]]-sum[ch[l][t^1]]) tmp+=two[i],r=ch[r][t^1],l=ch[l][t^1]; 24 else r=ch[r][t],l=ch[l][t]; 25 } 26 return tmp; 27 } 28 int main(){ 29 scanf("%d%d",&n,&m); 30 ++n; rep(i,2,n) scanf("%d",&a[i]); 31 two[0]=1; rep(i,1,25) two[i]=two[i-1]*2; 32 rep(i,1,n) b[i]=b[i-1]^a[i],rt[i]=add(rt[i-1],b[i]); 33 rep(i,1,m){ 34 scanf("%s",c); 35 if(c[0]=='A') { 36 ++n; 37 scanf("%d",&a[n]); 38 b[n]=b[n-1]^a[n]; 39 rt[n]=add(rt[n-1],b[n]); 40 }else { 41 scanf("%d%d%d",&l,&r,&x); 42 printf("%d\n",que(rt[l-1],rt[r],b[n]^x)); 43 } 44 } 45 }