可持久化字典树
引入
可持久化 Trie 的方式和可持久化线段树的方式是相似的,即每次只修改被添加或值被修改的节点,而保留没有被改动的节点,在上一个版本的基础上连边,使最后每个版本的 Trie 树的根遍历所能分离出的 Trie 树都是完整且包含全部信息的。
大部分的可持久化 Trie 题中,Trie 都是以 01-Trie 的形式出现的。
例题 最大异或和
对一个长度为 \(n\) 的数组 \(a\) 维护以下操作:
- 在数组的末尾添加一个数 \(x\),数组的长度 \(n\) 自增 \(1\)。
- 给出查询区间 \([l,r]\) 和一个值 \(k\),求当 \(l\le p\le r\) 时,\(k \oplus \bigoplus^{n}_{i=p} a_i\) 的最大值。
过程
这个求的值可能有些麻烦,利用常用的处理连续异或的方法,记 \(s_x=\bigoplus_{i=1}^x a_i\),则原式等价于 \(s_{p-1}\oplus s_n\oplus k\),观察到 \(s_n \oplus k\) 在查询的过程中是固定的,题目的查询变化为查询在区间 \([l-1,r-1]\) 中异或定值(\(s_n\oplus k\))的最大值。
继续按类似于可持久化线段树的思路,考虑每次的查询都查询整个区间。我们只需把这个区间建一棵 Trie 树,将这个区间中的每个树都加入这棵 Trie 中,查询的时候,尽量往与当前位不相同的地方跳。
查询区间,只需要利用前缀和和差分的思想,用两棵前缀 Trie 树(也就是按顺序添加数的两个历史版本)相减即得到该区间的 Trie 树。再利用动态开点的思想,不添加没有计算过的点,以减少空间占用。
C++ | |
---|---|
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 |
|
本页面的全部内容在 小熊老师 - 莆田青少年编程俱乐部 0594codes.cn 协议之条款下提供,附加条款亦可能应用