最近公共祖先(LCA)
最近公共祖先(LCA)
概念
在有根树中,两个点,会有共同的祖先,离他们两最近的公共祖先,即为LCA
求法
向上表记法O(n)
从一个点开始,向上遍历,把走过的点标记一下
再从另外一个点开始,向上遍历,如果走到的点已经被标记,即为LCA
最坏的情况是条链,\(O(n)\)的复杂度
倍增法 O(log n)
先预处理下各个点向上走\(2^k\)步所能走到的节点 \((1 \leq k \leq \log_{2}{n})\)
\(fa[i,k]\) 表示从i开始,向上走 \(2^k\) 步所在的节点
例如:
k | fa[i,k] |
---|---|
k==0 | fa[i,k] = fa[i,0] = i的父节点 |
k>0 | fa[i,k]=fa[ fa[i,k-1], k-1 ] |
再预处理下各点的深度,depth[i] 表示当前这个节点的深度
步骤:
-
先将两个点跳到同一层,即将深度更大的点跳到深度较浅的点的同一层
不妨令较深的节点为 x , 较浅的节点为 y
则有要跳跃的步数为 \(depth(x) - depth(y)\)
跳跃的步数又能够用二进制拼凑出来,即为 \(depth(x) - depth(y)\) 的二进制表示形式
\(fa[i,k]\) 为从 \(i\) 开始跳 \(2^k\) 步的节点。
那么只需要判断 \(depth(fa[x,k]) \geq depth(y)\) 即可
-
让两个点同时往上跳,直至他们的LCA的下一层
为什么不是到LCA,而是下一层,方便判断
若 \(fa[x,k] == fa[y,k]\) 我们只能说该点是 $x \(,\) y $ 的公共祖先,但是不一定是最近的公共祖先,有可能是LCA ,也可能是LCA上面的点。 那么同样的,利用倍增的思想,从大到小枚举 \(k\) 直至 \(fa[x,k] == fa[y,k]\)
所求的LCA 即为 \(fa[x,0]\) $ or$ $ fa[y,0]$
预处理 \(O(n log n)\)
查询 \(O(log n)\)