xxx 最小公共祖先(LCA)问题的 Tarjan 算法
字数 914 2025-11-17 11:06:31
xxx 最小公共祖先(LCA)问题的 Tarjan 算法
题目描述
给定一棵有根树和若干查询,每个查询要求两个节点的最近公共祖先(LCA)。例如,对于树:
1
/ \
2 3
/ \ \
4 5 6
查询 (4,5) 的 LCA 是 2,查询 (4,6) 的 LCA 是 1。要求高效处理多个查询。
解题过程
Tarjan 算法通过一次深度优先搜索(DFS)处理所有查询,利用并查集(Union-Find)记录节点关系,实现离线查询(所有查询已知)。
步骤详解
-
初始化
- 为每个节点创建集合,初始时每个节点独立一个集合。
- 记录每个节点的祖先:初始时祖先为自身。
- 记录访问状态:所有节点初始未访问。
-
DFS 遍历树
- 从根节点开始 DFS。访问节点 u 时:
a. 标记 u 为已访问。
b. 递归处理 u 的所有子节点。处理完子节点后,将子节点所在集合与 u 合并,并设置 u 为合并后集合的代表(祖先)。
- 从根节点开始 DFS。访问节点 u 时:
-
处理查询
- 当节点 u 的子树遍历完成后,检查所有与 u 相关的查询 (u, v)。
- 若 v 已被访问,则查询 (u, v) 的 LCA 为 v 当前所在集合的祖先。
- 由于 DFS 特性,当 v 已被访问时,v 所在集合的祖先即为 u 和 v 的 LCA。
-
并查集优化
- 使用路径压缩和按秩合并优化并查集操作,使每次操作接近常数时间。
示例演示
对上述树和查询 (4,5), (4,6):
- DFS 访问节点 4:标记访问,无子节点。处理查询 (4,5):5 未访问,暂不处理。
- 回溯到节点 2:先处理子节点 5。访问 5 后,合并 {4} 和 {5} 到集合 {2},祖先设为 2。
- 在节点 2 处理查询 (4,5):5 已访问,LCA 为 5 的集合祖先 2。
- 继续 DFS 至节点 6,回溯到 3 和 1。在节点 1 处理查询 (4,6):6 已访问,LCA 为 6 的集合祖先 1。
复杂度分析
- 时间复杂度:O(n + α(n)Q),其中 n 为节点数,Q 为查询数,α 为反阿克曼函数。
- 空间复杂度:O(n) 存储树和查询。
关键点
- 利用 DFS 遍历顺序和并查集动态维护集合,确保查询时能快速确定 LCA。
- 离线算法需预先知道所有查询,适合批量处理场景。