可持久化 Trie
可持久化 Trie
Trie 树的可持久化思路与线段树/平衡树类似,每次都 clone 一个新的节点即可。
唯一需要注意的是实现上的问题,因为 Trie 树一般不写递归,因此要注意实现。
一般实现的可持久化 Trie 都是 01Trie。
Luogu P4735 最大异或和
给定一个长度为 \(n\) 的序列 \(a_1,a_2,\cdots,a_n\) 和 \(m\) 次操作:
- 给定 \(x\),在序列末尾加入 \(x\)。
- 给定 \(l,r,x\),对于 \(l\leq i\leq r\),输出 \(a_i\oplus a_{i+1}\oplus\cdots\oplus a_n\oplus x\) 的最大值。
显然可以维护前缀异或和 \(s_1,s_2,\cdots,s_n\),即对于 \(i\in[l,r]\),求 \(x\oplus s_n\oplus s_{i-1}\) 最大值。
发现 \(x\oplus s_n\) 为定值,考虑 01Trie 查询 \(s_{i-1}\)。
但是需要区间查询,可以使用可持久化 01Trie,加入一个数即一个新版本。
查询时,前缀和差分即可判断存不存在 \(0\) 或 \(1\)。
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
constexpr const int N=3e5,V=30;
int n;
struct trie{
int size,root[N<<1|1];
struct node{
int m[2];
int value;
}t[N*100+1];
trie(){
size=1;
root[0]=1;
}
int clone(int p){
t[++size]=t[p];
return size;
}
void insert(int v,int i,int x){
int p=root[i]=clone(root[v]);
for(int j=V;j>=0;j--){
int bit=x>>j&1;
t[p].m[bit]=clone(t[p].m[bit]);
p=t[p].m[bit];
t[p].value++;
}
}
int query(int l,int r,int x){
int p=root[r],q=root[l-1];
int ans=0;
for(int i=V;i>=0;i--){
int bit=x>>i&1;
if(t[t[p].m[!bit]].value-t[t[q].m[!bit]].value){
p=t[p].m[!bit];
q=t[q].m[!bit];
ans|=1<<i;
}else{
p=t[p].m[bit];
q=t[q].m[bit];
}
}
return ans;
}
}t;
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int m;
cin>>n>>m;
int s=0;
t.insert(0,1,0);
for(int i=1;i<=n;i++){
int x;
cin>>x;
s^=x;
t.insert(i,i+1,s);
}
while(m--){
char op;
int l,r,x;
cin>>op;
switch(op){
case 'A':
int x;
cin>>x;
s^=x;
n++;
t.insert(n,n+1,s);
break;
case 'Q':
cin>>l>>r>>x;
cout<<t.query(l,r,x^s)<<'\n';
break;
}
}
cout.flush();
/*fclose(stdin);
fclose(stdout);*/
return 0;
}

浙公网安备 33010602011771号