最大异或和
可持久trie板题
实现两个操作:
- 在序列 a a a末尾添加一个数 x x x,并且序列长度增大 1 1 1
- 询问求一个位置 p ∈ [ l , r ] p\in [l,r] p∈[l,r],最大化 ( ⨁ p n a i ) ⊕ x (\bigoplus_p^na_i)\oplus x (⨁pnai)⊕x,其中 x x x为读入数
考虑前缀和,记
⨁
1
i
a
i
=
s
i
\bigoplus_1^ia_i=s_i
⨁1iai=si,记
v
a
l
=
s
n
⊕
x
val=s_n\oplus x
val=sn⊕x
现目标最大化
a
p
⊕
v
a
l
,
p
∈
[
l
−
1
,
r
−
1
]
a_p\oplus val,p\in[l-1,r-1]
ap⊕val,p∈[l−1,r−1]
进阶指南写得真的好啊:一步一步加限制,想解法
不考虑限制,朴素trie即可结局
再考虑
p
≤
r
−
1
p\le r-1
p≤r−1的限制,运用可持久trie,在root[r-1]
里访问即可
最后考虑
p
∈
[
l
−
1
,
r
−
1
]
p\in[l-1,r-1]
p∈[l−1,r−1],即访问时不能访问到
<
l
−
1
<l-1
<l−1的点,维护一个tag
即可,记录节点是第几个二进制数能访问到的,且最大化tag
tag
的算法一定义一下
注意空间
听说20倍到32倍左右
#include<bits/stdc++.h>
using namespace std;
#define in Read()
typedef long long ll;
ll in{
ll i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<3)+(i<<1)+ch-48,ch=getchar();
return i*f;
}
const int N=1e6+5;
int n,m,sz,trie[N*24][2],tag[N*24],root[N],s[N];
char opt[3];
void insert(int t,int k,int pre,int now){
if(k<0){
tag[now]=t;
return;
}
int c=(s[t]>>k)&1;
if(pre) trie[now][c^1]=trie[pre][c^1];
trie[now][c]=++sz;
insert(t,k-1,trie[pre][c],trie[now][c]);
tag[now]=max(tag[trie[now][0]],tag[trie[now][1]]);
return;
}
int query(int val,int k,int now,int low){
if(k<0) return val^s[tag[now]];
int c=(val>>k)&1;
if(tag[trie[now][c^1]]>=low)
return query(val,k-1,trie[now][c^1],low);
else
return query(val,k-1,trie[now][c],low);
}
int main(){
n=in,m=in;
tag[0]=-1;
root[0]=++sz;
insert(0,23,0,root[0]);
for(int i=1;i<=n;++i){
int x=in;
s[i]=s[i-1]^x;
root[i]=++sz;
insert(i,23,root[i-1],root[i]);
}
for(int i=1;i<=m;++i){
scanf("%s",opt);
if(opt[0]=='A'){
int x=in;
root[++n]=++sz;
s[n]=s[n-1]^x;
insert(n,23,root[n-1],root[n]);
}else{
int l=in,r=in,x=in;
int val=s[n]^x;
printf("%d\n",query(val,23,root[r-1],l-1));
}
}
return 0;
}