4 Graph
最近公共祖先LCA
定义
最近公共祖先简称 LCA(Lowest Common Ancestor)。两个节点的最近公共祖先,就是这两个点的公共祖先里面,离根最远的那个。 为了方便,我们记某点集 的最近公共祖先为 或 。
性质
- ;
- 是 的祖先,当且仅当 ;
- 如果 不为 的祖先并且 不为 的祖先,那么 分别处于 的两棵不同子树中;
- 前序遍历中, 出现在所有 中元素之前,后序遍历中 则出现在所有 中元素之后;
- 两点集并的最近公共祖先为两点集分别的最近公共祖先的最近公共祖先,即 ;
- 两点的最近公共祖先必定处在树上两点间的最短路上;
- ,其中 是树上两点间的距离, 代表某点到树根的距离。
求法
朴素算法
过程
可以每次找深度比较大的那个点,让它向上跳。显然在树上,这两个点最后一定会相遇,相遇的位置就是想要求的 LCA。 或者先向上调整深度较大的点,令他们深度相同,然后再共同向上跳转,最后也一定会相遇。
性质
朴素算法预处理时需要 dfs 整棵树,时间复杂度为 ,单次查询时间复杂度为 。如果树满足随机性质,则时间复杂度与这种随机树的期望高度有关。
倍增算法
过程
倍增算法是最经典的 LCA 求法,他是朴素算法的改进算法。通过预处理 数组,游标可以快速移动,大幅减少了游标跳转次数。 表示点 的第 个祖先。 数组可以通过 dfs 预处理出来。
现在我们看看如何优化这些跳转:
在调整游标的第一阶段中,我们要将 两点跳转到同一深度。我们可以计算出 两点的深度之差,设其为 。通过将 进行二进制拆分,我们将 次游标跳转优化为「 的二进制表示所含 1
的个数」次游标跳转。
在第二阶段中,我们从最大的 开始循环尝试,一直尝试到 (包括 ),如果 ,则 ,那么最后的 LCA 为 。

复杂度
倍增算法的预处理时间复杂度为 ,单次查询时间复杂度为 。
另外倍增算法可以通过交换 fa
数组的两维使较小维放在前面。这样可以减少 cache miss 次数,提高程序效率。
倍增求LCA模板
例题:
Status
Problem
Tags