基础树论
树上的基础知识,也有一些科技。
LCA 的求法
树剖
倍增
跳到同一深度后记得判两个点相同的情况。
ST表
除了这个要么熟知要么没什么用。学习一下。
预处理 \(O(n\log n)\),查询 \(O(1)\)。可以用 DFS 序或者欧拉序实现。但是欧拉序的常数较大,还是用 DFS 序。
主要参考 Alex_Wei 的 blog
欧拉序
每次到一个点就记录一次,因为 \(\sum d_u=2(n-1)\),而且根结点会多记录一次,所以欧拉序长为 \(2n-1\)。
我们记录每个点第一次出现的位置 \(f_u\)。那么 \(\text{LCA}(u,v)\) 在欧拉序上必然在 \(f_u\) 和 \(f_v\) 之间出现,于是求区间内深度最小的位置即可,用 ST 表做。
DFS 序
欧拉序的常数还是太大了,我们考察两个点 \(u,v\) 的 \(dfn\)。
不妨 \(dfn_u<dfn_v\),分讨一下:
-
如果 \(u\) 不是 \(v\) 的祖先,那么设 \(d=\text{LCA}(u,v)\),\(d\) 到 \(v\) 的路径上的 \(d\) 的儿子必然在 \([dfn_u,dfn_v]\) 中,且是这一段中深度最小的。
-
如果 \(u\) 是 \(v\) 的祖先,那么不妨将上面的区间修改为 \([dfn_u+1,dfn_v]\),这样还是能用上面的做法。而且容易发现修改后的做法对第一种情况也适用。
所以只需求 \([dfn_u+1,dfn_v]\) 这段区间内深度最小的点的父亲即可。唯一需要特判的是 \(u=v\) 的情况。
一种避免记录父亲和深度的方法是在 ST 表底层记录每个点的父亲,按 \(dfn\) 比较大小。不难发现这样是正确的。

浙公网安备 33010602011771号