dfs 序求 lca 学习笔记
作用大概就是一种很好写,而且常数还小的求 lca 的办法。
dfs 序有性质,若 \(u\) 是 \(v\) 祖先则 \(\operatorname{dfn}_u<\operatorname{dfn}_v\)。
钦定 \(\operatorname{dfn}_u<\operatorname{dfn}_v\),考虑 \(u\) 和 \(v\) 的最近公共祖先 \(d\) 的两种情况:
- \(u\) 是 \(v\) 祖先,则这种情况下我们发现 \(u\) 为 \(\operatorname{dfn}_x\in [\operatorname{dfn}_u,\operatorname{dfn}_v]\) 中深度最小的节点 \(x\)。
充分性:若 \(u\) 为 \(v\) 祖先,则 \([\operatorname{dfn}_u,\operatorname{dfn}_v]\) 这个区间内肯定都是 \(u\) 子树内的结点,由于 dfs 序的性质不可能有节点比 \(u\) 的深度还小。
必要性类似。
- \(u\) 不是 \(v\) 祖先,则这种情况下 dfs 序的遍历肯定是 \(d\to u\to d\to v\),但此时我们发现 \([\operatorname{dfn}_u,\operatorname{dfn}_v]\) 这个区间只能包含下图的节点:

发现这段区间肯定会包含一个 \(d\) 的儿子,所以 \(d\) 就是这段区间内深度最小的节点的父节点。
判断 \(u\) 是否为 \(v\) 的祖先其实好搞,但有一个更加优雅的做法。
我们发现这两种情况本质上来讲可以合并成一个情况,即 \(d\) 为 \([\operatorname{dfn}_u+1,\operatorname{dfn}_v]\) 这段区间内深度最小的节点(若有多个,则本质上来讲就是 \(u\to v\) 遍历的路径中间多加了几个 \(d\) 的儿子的子树,随便选一个即可)的父亲。
稍微想想边界情况,证明不难。
然后有了这个性质,就可以 ST 表 \(O(n\log n)\) 预处理和 \(O(1)\) 查询了。

浙公网安备 33010602011771号