xxx 最小公共祖先(LCA)问题的Tarjan算法
字数 1025 2025-10-30 21:15:36
xxx 最小公共祖先(LCA)问题的Tarjan算法
题目描述
给定一棵有根树(节点数为 \(n\))和若干查询(每个查询包含两个节点 \(u\) 和 \(v\)),要求快速求出每对节点的最近公共祖先(LCA)。例如,若树为 1-2-3(根为1),则 LCA(2,3)=2。Tarjan算法通过离线处理(预先收集所有查询)和并查集(Union-Find)优化,在 \(O(n + q \alpha(n))\) 时间内解决(\(q\) 为查询数,\(\alpha\) 为反阿克曼函数)。
解题步骤
-
预处理与初始化
- 存储树的邻接表结构,并记录根节点。
- 收集所有查询,为每个节点
u维护一个查询列表,每个查询包含另一节点v和查询索引。 - 初始化并查集,每个节点初始父节点为自身,并标记为未访问。
-
深度优先搜索(DFS)遍历
- 从根节点开始DFS。遍历到节点
u时,先递归处理其所有子节点。 - 关键思想:处理完子树后,将子树的并查集合并到当前节点
u,保证子树中所有节点的代表元(并查集根)为u。
- 从根节点开始DFS。遍历到节点
-
查询处理与并查集结合
- 当节点
u的DFS完成时,标记u为已访问,并检查所有与u相关的查询(u, v)。 - 若
v已被访问过,则查询(u, v)的LCA即为v在并查集中的当前代表元(因为v的子树尚未合并到其祖先,代表元即v所在子树的根,也就是LCA)。 - 使用并查集的“查找”操作快速获取代表元。
- 当节点
-
合并操作
- 递归回溯时,将当前节点
u与父节点合并(通过并查集的“合并”操作),使父节点成为子树的新代表元。
- 递归回溯时,将当前节点
示例演示
树:边为 (1,2), (1,3), (2,4), (2,5)(根为1),查询 LCA(4,5) 和 LCA(4,3)。
- DFS到节点4:标记访问,查询
(4,5)中5未访问,暂不处理;回溯到2时合并4到2。 - DFS到节点5:标记访问,查询
(5,4)发现4已访问,4的代表元为2,故LCA(4,5)=2。 - DFS到节点3:标记访问,查询
(3,4)中4已访问,4的代表元为1(因为2已合并到1),故LCA(3,4)=1。
关键点
- 离线算法:需预先知道所有查询,但效率高。
- 并查集优化路径压缩,使操作接近常数时间。
- 每个查询仅在两个节点均被访问时才可计算LCA。