理解路径复制(path copying)为何让一次单点修改只新增 $O(\log V)$ 个节点;学会用两个前缀版本相减表示区间频次,并推广到树路径的四版本容斥。
前置:普通线段树、离散化、LCA。
root[r]-root[l-1] 的节点计数代表什么?持久化不是复制整棵树,而是把节点视为不可变对象。修改节点前创建副本,递归修改一个儿子,另一个儿子仍指向旧节点。若初始/空树节点编号为 0,一次插入新增一条值域路径。
第 $k$ 小查询在左右版本的左儿子计数差上决策:若左半元素数至少 $k$,进入左半;否则减去它并进入右半。这个过程同时完成选择与二分,不需要外层答案二分。
四版本容斥时把 count = countR(u)+countR(v)-countR(w)-countR(pw) 直接换成四个对应儿子的计数,其余逻辑与两根版本相同。
初始节点 + 修改次数 * (logV+1),不足会越界。依次从前一版本插入 $a_i$ 得到 root[i]。查询时,当前值域左半的区间元素数由两个根左儿子计数相减得到。若不少于 $k$,答案必在左半;否则左半全部排在答案前,转右半并令 $k$ 减该数。区间每次减半,抵达叶子时其秩唯一。
预处理 $O(n\log n)$,每问 $O(\log n)$,节点 $O(n\log n)$。
root[0] = empty_value_tree
for i in 1..n: root[i] = insert_copy(root[i-1], rank(a[i]))
kth(left_root, right_root, k, value_interval):
left_count = count(right_root.left) - count(left_root.left)
if k <= left_count: recurse on both left children
else: recurse on both right children with k -= left_count
kth4(u, v, w, pw, k, value_interval):
left_count = count(u.left)+count(v.left)-count(w.left)-count(pw.left)
if k <= left_count: recurse on (u.left, v.left, w.left, pw.left)
else: recurse on right children with k -= left_count
root[u]+root[v]-2*root[w] 会把 LCA 权值也删掉,必须改成减 root[w] 与 root[parent(w)]。任意值域区间内,根到 $u$ 与根到 $v$ 的计数相加,公共前缀根到 LCA 被算两次。减去根到 LCA 与根到 LCA 父亲,恰保留路径并让 LCA 计一次。把第 k 小的左右计数公式替换为四根容斥即可;LCA 用倍增预处理。
预处理 $O(n\log n)$,每问 LCA 与选择均 $O(\log n)$,空间 $O(n\log n)$。
DFS/BFS from tree root:
version[v] = insert_copy(version[parent[v]], rank(weight[v]))
w = LCA(u, v)
pw = parent(w), or empty version when w is root
kth4(version[u], version[v], version[w], version[pw], k, value_interval)
初始数组建立普通和树。单点赋值沿路径复制,重新计算新节点和;不在路径上的节点共享且值未变。复制操作追加同一个根编号。由节点不可变性,任何旧根可达的节点内容永不被修改,所以所有历史/分支版本语义保持;新根恰反映指定单点更新。
建树 $O(n)$,修改/查询 $O(\log n)$,复制 $O(1)$,空间 $O(n+q\log n)$。
roots = [build(initial_array)]
set(version, position, value): roots[version] = update_copy(roots[version], position, value)
sum(version, l, r): query(roots[version], l, r)
copy(version): roots.append(roots[version])
主席树是“可持久化权值线段树”的常见竞赛称呼,不等于所有持久化线段树。若修改是区间 Lazy,路径复制还要连同标记语义一起保持不可变,复杂度与实现风险更高。
先把节点池缩小到故意溢出,学会估算容量;用朴素排序/数组副本对拍三题。路径题重点打印 LCA 为端点、LCA 为根、u=v 三种容斥结果。