定义:
Lca(最近公共祖先) 指在一棵有根树中任意 2 2 2个节点 u , v u,v u,v最近的公共祖先。
如下图:
如右图,结点 4 , 6 4,6 4,6的公共祖先有 1 、 2 1、2 1、2,但最近的公共祖先是 2 2 2,即 L c a ( 4 , 6 ) = 2 Lca(4,6) = 2 Lca(4,6)=2。
如何求得 u , v u,v u,v的最近公共祖先呢?
算法一:暴力
现在有一个最朴素的算法,暴力。
- 1 1 1.u,v中深度大的往上走,直到 u , v u,v u,v深度相同。若此时 u = = v u==v u==v,则已找到,输出 u u u。
- 2 2 2.如果深度相同 u , v u,v u,v却没有相等,就令 u , v u,v u,v一起往上走,直到走到同一个结点,输出 u u u。
算法时间复杂度为 O ( n ) O(n) O(n)。
代码如下:
int Lca(int u,int v)
{
//fa 表示每个节点的父亲
//dep 表示每个节点深度
//dep,fa数组都可以预处理出来
if (fep[u]>dep[v]) swap(u,v);
while (dep[v]>dep[u]) v=fa[v];
//令v,u在同一深度
if (u==v) return u;
while (u!=v)
{
u=fa[u];
v=fa[v];
}
return u;
}
算法二:倍增法
思想:注意到 u , v u,v u,v向上走到最近公共祖先 w w w之前, u , v u,v u,v所在的结点不相同。而到达最近公共祖先 w w w后,再往上走仍是 u , v u,v u,v的公共祖先,即 u , v u,v u,v走到同一个结点。这具有二分性质。于是我们可以预处理出一个