Persistent Segment Tree
Persistent Segment Tree
The full name of Persistent Segment Tree is Persistent Weight Segment Tree. See Zhihu discussion.
About Functional Segment Tree
Functional Segment Tree refers to a segment tree that uses functional programming ideas. In functional programming, computations are treated as mathematical functions, and mutable states or variables are avoided. It is not difficult to see that functional segment trees are fully persistent.
Introduction
First, let's introduce a problem: Given a sequence \(a\) of \(n\) integers, for a specified closed interval \([l, r]\), query the \(k\)-th smallest value within that interval.
How would you solve it?
One feasible solution is: use a Persistent Segment Tree. The main idea of the Persistent Segment Tree is: save the historical version after each insertion operation to facilitate querying the \(k\)-th smallest value in an interval.
How to save? Simply and brutally, create a new segment tree each time.
Wouldn't that blow up the space?
Explanation
We analyze and find that the number of nodes modified in each update operation is the same.
(For example, in the figure below, the node corresponding to weight 1 in \([1,8]\) is modified, and the red points are the changed nodes)

Only \(O(\log{n})\) nodes are changed, forming a chain, meaning the number of nodes changed each time = the height of the tree.
Note that the Persistent Segment Tree cannot use heap storage, meaning we cannot use \(x\times 2\), \(x\times 2+1\) to represent left and right children. Instead, we should dynamically allocate nodes and save the left and right child indices for each node.
So, by recording the left and right children and saving the root node when each number is inserted, we can achieve persistence.
Let's simplify the problem: each time, find the \(k\)-th smallest value in the interval \([1,r]\).
How to do it? Just find the root node version when inserting r, and then use an ordinary Weight Segment Tree (also called Key-Value Segment Tree / Value Range Segment Tree).
I believe everyone can understand this. Back to the original problem—finding the \(k\)-th smallest value in the interval \([l,r]\).
Here we relate to another concept: Prefix Sum.
This little thing cleverly uses the property of interval subtraction, achieving \(O(1)\) answers to each query through preprocessing.
We can find that the statistical information of the Persistent Segment Tree also satisfies this property.
So... if we need the statistical information of \([l,r]\), we just need to subtract the information of \([1,l - 1]\) from the information of \([1,r]\).
Thus, the problem is solved!
Regarding the space issue, let's analyze: Since we dynamically allocate nodes, a segment tree will only have \(2n-1\) nodes.
Then, there are \(n\) modifications, each adding at most \(\lceil\log_2{n}\rceil+1\) nodes. Therefore, in the worst case, the total number of nodes after \(n\) modifications will reach \(2n-1+n(\lceil\log_2{n}\rceil+1)\).
For this problem, \(n \leq 10^5\), a single modification adds at most \(\lceil\log_2{10^5}\rceil+1 = 18\) nodes, so the total number of nodes after \(n\) modifications is \(2\times 10^5-1+18\times 10^5\), ignoring \(-1\), roughly \(20\times 10^5\).
Finally, a piece of advice: Never be stingy with space (in most problems, the space limit is relatively lenient, so generally there's no need to worry about exceeding the space limit)! Be bold, directly use \(2^5\times 10^5\), close to twice the original space (i.e., n << 5).
Implementation
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 | |
Extension: Persistent Union-Find Based on Persistent Segment Tree
The Persistent Segment Tree is a convenient way to implement Persistent Union-Find. Here is also an example implementation of Persistent Union-Find based on Persistent Segment Tree.
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 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | |
References
https://en.wikipedia.org/wiki/Persistent_data_structure
https://www.cnblogs.com/zinthos/p/3899565.html
本页面最近更新:,更新历史
发现错误?想一起完善? 在 GitHub 上编辑此页!
本页面贡献者:OI-wiki
本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用