一. 离线Tarjan算法
LCA问题(lowest common ancestors):在一个有根树T中,两个节点和
的最近公共祖先,指的是二者的公共祖先中深度最高的节点。给定任意两个树中的节点,求它们的最近公共祖先。
对于二分查找树、二叉树,可以用普通的dfs实现,但对于多叉树、查询次数频繁的情况下,离线Tarjan算法的优点就显现出来了。由于对树上所有节点只进行一次遍历,因此需要提前指定所有查询,所以才称为offline。
算法思路是:每次处理一个节点时,先递归处理其儿子节点,保证:若查询的节点pair均在该子树中,则处理完这个节点后,这些查询也已经处理完毕,否则其中一个节点在另一个子树中,这对节点的公共祖先至少应该是
的父节点。具体是对每个节点,都维护一个集合,每当一个节点处理完毕,就与其父节点所在集合进行合并。处理完毕指的是:以该节点为根节点的子树中的所有节点都被访问过并且返回了。因此以某个元素为代表元的集合内,保存的都是当前已经处理完毕的子孙节点。
算法的伪代码如下:初始时每个节点颜色均为white
LCA(u)
1 MakeSet(u)
2 u.ancestor := u
3 for each v in u.children do
4 LCA(v)
5 Union(u, v)
6 Find(u).ancestor := u
7 u.color := black;
8 for each v such that {u, v} in P do
9 if v.color == black
10 print "Tarjan's lowest common Ancestor of " + u +
" and " + v + " is " + Find(v).ancestor + "."</span>
下面首先对算法导论中的习题进行证明:
(1)证明:对每一对,第10行恰执行一次
证明:因为每个节点只调用一次LCA,对任意节点对,不失一般性,假设
先被处理完&