最近公共祖先(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] 表示当前这个节点的深度

步骤:

  1. 先将两个点跳到同一层,即将深度更大的点跳到深度较浅的点的同一层

    ​ 不妨令较深的节点为 x , 较浅的节点为 y

    ​ 则有要跳跃的步数为 \(depth(x) - depth(y)\)

    ​ 跳跃的步数又能够用二进制拼凑出来,即为 \(depth(x) - depth(y)\) 的二进制表示形式

    \(fa[i,k]\) 为从 \(i\) 开始跳 \(2^k\) 步的节点。

    ​ 那么只需要判断 \(depth(fa[x,k]) \geq depth(y)\) 即可

  2. 让两个点同时往上跳,直至他们的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)\)

    P3379 【模板】最近公共祖先(LCA)

    1171. 距离

    小A的最短路

posted @ 2023-11-26 08:33  xlxDH  阅读(20)  评论(0编辑  收藏  举报