【讲解+模板】最近公共祖先(LCA)(倍增)

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

阅读须知:我认为读者已经掌握(或了解)了:

  1. 倍增思想
  2. 树(图)的基本概念及简单实现
  3. 存图与建图
  4. dfs

嗯,我们来看看最近公共祖先(LCA)的一种实现方式——倍增。

最近公共祖先

话说什么是最近公共祖先呢?emmm……大家如果知道树的话,应该就知道父亲节点与儿子节点了吧,那么祖先就是父亲的父亲的父亲的……;总之在同一条树链上,若x的深度小于y的深度,则称x是y的祖先。公共祖先,顾名思义就是两个点共同拥有的祖先;但是若x是y的祖先,则他们的共同祖先是x(很奇怪是不是)。最近公共祖先可以依字面意思理解,即“最近的”公共祖先。下面附图说明~
1【图1】
如上图4和7的公共祖先有5、10,最近公共祖先为5;
3与20的公共祖先和最近公共祖先都是10;
2和3的公共祖先是3、5、10,最近公共祖先是3。
怎么样,对最近公共祖先是不是有些了解了。
下面我们再来看两张图~
2【图2】

3【图3】
请读者们仔细比对上面两张图,会发现,选择不同的根节点会使得两点之间有着不同的最近公共祖先。

倍增

关于实现LCA,想必大家都有暴力的思路,不断询问x与y的父亲节点,直到发现他们询问到相同的父亲节点位置,这当然会超时!所以,我们着查找【滑稽】,这就是倍增的思想。
我们使用一个数组lst[i][j]表示从i这个点向上跳2^j次所对应的点,即节点i的第2^j个父亲节点的编号。比如说上面第二个图中lst[5][0]=2,lst[5][1]=1。
请读者们细细体会下面的转化【很重要】(可以画一颗树试一试):

lst[son][i + 1] = lst[ lst[son][i] ][i]

倍增LCA的实现

1.建图(建议使用链式前向星)
2.预处理,更新lst数组
3.查询
下面分条作答

1.建图

链式前向星存图【不了解的话建议百度】

//建树一般不用存边权,建树一般要存双向边
struct EDGE
{
    int to;  //到达的点
    int next; //上一条边
    int w;  //边权
}edge[2 * max_data];  //双向边
int edge_size = 0;  //前向星数组模拟指针
int head[max_data];  //起点

void add(int u, int v, int w)
{
    edge[++edge_size].next = head[u];
    edge[edge_size].to = v;
    edge[edge_size].w = w;
    
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值