可持久化线段树
看这个。
可持久化字典树
最大异或和
考虑设 \(s\) 为 \(a\) 的前缀异或和数组,我们最终的答案就是找一个 \(p\in[l-1,r-1]\),然后求出 \(s_n\operatorname{xor} x\operatorname{xor} s_p\)。
首先,对于最大异或数对问题,可以使用 \(01\) \(trie\) 解决,这里不再赘述。
类似于可持久化线段树,我们查询版本 \([l,r]\) 就是对前 \(r\) 个版本与前 \(l-1\) 个版本做差得到的,于是我们对于每个版本,先继承上一个版本,然后插入这个数。
然后我们每次修改就是开启一个新版本然后插入一个数,查询直接按照查询最大异或数对的方式对 \(s_n\operatorname{xor} x\) 进行查询即可。
代码:
#include<bits/stdc++.h>
#define int long long
#define N 600005
#define K 31
using namespace std;
int n,q,a[N],s[N];
struct trie{
int rt[N],tr[N*K][2],val[N*K],idx;
void ins(int las,int p,int v){
for(int i=K-1;~i;i--){
val[p]=val[las]+1;
int t=v>>i&1;
tr[p][t]=++idx;
tr[p][!t]=tr[las][!t];
p=tr[p][t];
las=tr[las][t];
}
val[p]=val[las]+1;
}
int qry(int p,int q,int v){
int res=0;
for(int i=K-1;~i;i--){
int t=v>>i&1;
if(val[tr[q][!t]]-val[tr[p][!t]]){
res+=1<<i;
p=tr[p][!t];
q=tr[q][!t];
}
else{
p=tr[p][t];
q=tr[q][t];
}
}
return res;
}
}trie;
signed main(){
cin>>n>>q;
for(int i=1;i<=n;i++){
cin>>a[i];
s[i]=s[i-1]^a[i];
}
for(int i=1;i<=n;i++){
trie.rt[i]=++trie.idx;
trie.ins(trie.rt[i-1],trie.rt[i],s[i]);
}
while(q--){
char op;
int l,r,x;
cin>>op;
if(op=='A'){
cin>>a[++n];
s[n]=s[n-1]^a[n];
trie.rt[n]=++trie.idx;
trie.ins(trie.rt[n-1],trie.rt[n],s[n]);
}
else{
cin>>l>>r>>x;
l--;r--;
if(l==0)cout<<max(s[n]^x,trie.qry(trie.rt[0],trie.rt[r],s[n]^x))<<'\n';
else cout<<trie.qry(trie.rt[l-1],trie.rt[r],s[n]^x)<<'\n';
}
}
return 0;
}
标签:持久,val,int,tr,trie,异或,数据结构,las
From: https://www.cnblogs.com/zxh923aoao/p/18407600