跳转至

最近公共祖先

定义

最近公共祖先(LCA,Lowest Common Ancestor),顾名思义就是最近的公共祖先。

一个集合 SS 的最近公共祖先 LCA(S)=LCA(s1,s2,,sk)\text{LCA}(S)=\text{LCA}(s_1,s_2,\dots,s_k) 定义为:

这个集合中所有节点,其祖先的交集中,离根最远的那个。

性质

在数值的关系上:

  1. LCA({u})=u\text{LCA}(\{u\})=u
  2. LCA(AB)=LCA{LCA(A),LCA(B)}\text{LCA}(A\cup B)=\text{LCA}\{\text{LCA}(A),\text{LCA}(B)\}
  3. d(u,v)=h(u)+h(v)2LCA{u,v}d(u,v)=h(u)+h(v)-2\text{LCA}\{u,v\}

在形态的关系上:

  1. uuvv 的祖先,当且仅当 LCA{u,v}=u\text{LCA}\{u,v\}=u
  2. 两个点的最近公共祖先一定在这两个点的最短路上。

算法

由于我们可以把一个集合不断拆分,最终将问题拆分为:求任意两个点 u,vu,v 的 LCA。

朴素算法

cc 表示节点 u,vu,v 的 LCA,考虑到 cc 深度一定比 u,vu,v 都要小。

于是我们可以先把 u,vu,v 中比较深的那一个往上跳,最终得到 u,vu',v'

即,从两个点一步一步往上跳,跳到同一高度后再一起跳。

优化算法

很多,我们在此列举:

算法 预处理复杂度 查询复杂度 特点
倍增 O(nlogn)\mathcal O(n\log n) O(logn)\mathcal O(\log n) 跑满 log\log
欧拉序 O(nlogn)\mathcal O(n\log n) O(1)\mathcal O(1) 常数较大
DFS 序 O(nlogn)\mathcal O(n\log n) O(1)\mathcal O(1) 常数较小
树链剖分 O(n)\mathcal O(n) O(logn)\mathcal O(\log n) 常数很小

还有一些奇妙的,例如 Tarjan、四毛子、±1 RMQ 等,暂时不写。

  • 一般来说,询问量很大的时候用 DFS 序,否则用树链剖分。

  • 当求 LCA 不是复杂度瓶颈的时候,可以用倍增(好写)。

我们开始详细讲解每一个。


Page Top