LCA--倍增法

Posted darlingroot

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LCA--倍增法相关的知识,希望对你有一定的参考价值。

一般来求LCA有3种方法

1.倍增

2.RMQ+欧拉序

3.tarjan(离线)

 

本文将倍增求lca

这个算法是很常见很常见

也是较好理解的

(我也不明白假期学长讲的时候我为什么死活都不明白

 自闭qwq

 对不起学长qwq

 明明学长讲的是最好的qwq

 想学长了qwq)

 

---------------------------------------------------------------------------

 

一、基础概念

LCA定义:

  LCA(Lowest Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先。

 

如图,结点4,6的公共祖先有1、2,但最近的公共祖先是2,即Lca(4,6) = 2

技术图片

 

 

显然遇到这个问题

首先会想到暴力

再一算

时间复杂度"仅仅"是O(n)而已啦

可是如果有q次询问呢

比如说洛谷板子题

n和q(这里的q即板子题中的m都是5 * 105的级别的

那么n*q就是一个不小的数了

那么暴力一定是过不了的了

那么就只能优化优化了

 

 

--------------------------------------------------------------------

 

倍增法:

 

注意到u,v走到最近公共祖先w之前,u,v所在结点不相同。

而到达最近公共祖先w后,再往上走仍是u,v的公共祖先,即u,v走到同一个结点,这具有二分性质。

于是可以预处理出一个2k的表,

fa[k][u]表示u往上走2k步走到的结点,令根结点深度为0,则2k>depth[u]时,令fa[k][u]=-1(不合法情况的处理)

 

 

不妨假设depth[u] < depth[v]

①将v往上走d = depth[v] - depth[u]步,此时u,v所在结点深度相同,该过程可用二进制优化。

由于d是确定值,将d看成2的次方的和值,d = 2k1 + 2k2 + ... + 2km,利用fa数组,如v = fa[k1][v],v = fa[k2][v]加速。

②若此时u = v,说明Lca(u,v)已找到

③利用fa数组加速u,v一起往上走到最近公共祖先w的过程。

令d = depth[u] - depth[w],虽然d是个未知值,但依然可以看成2的次方的和。

从高位到低位枚举d的二进制位,设最低位为第0位,若枚举到第k位,有fa[k][u] != fa[k][v],则令u = fa[k][u],v = fa[k][v]。

最后

最近公共祖先w = fa[0][u] = fa[0][v],即u和v的父亲

 

技术图片

 

 

技术图片

 

 

如何预处理?
    k=0时,fa[k][u]为u在有根树中的父亲,令根结点fa[k][root]=-1。

 k>0时,fa[k][u]=fa[k-1][fa[k-1][u]]。树的高度最多为n,k是logn级别。

 

时间复杂度?
    预处理O(nlogn)
    单次查询O(logn)

 

来个板子题也很好理解呀(传送门

上面提到过的

罗姑上也有板子题

但是我最近是由hdu的oj写的

正好还有那个的代码就直接拿过来了

 

以上是关于LCA--倍增法的主要内容,如果未能解决你的问题,请参考以下文章

倍增法求LCA

倍增法求LCA——在线

lca(最近公共祖先(在线)) 倍增法详解

poj1470 LCA倍增法

hdu2586 lca倍增法

倍增法求LCA