可持久化 Trie

例题:洛谷 P4735

Posted by TH911 on February 9, 2026

可持久化 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$。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
//#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;
}