【日志】LCA 倍增求法

本文介绍了图论中求解最近公共祖先(LCA)的倍增方法。通过倍增思想,可以高效地找到树上任意两点的LCA。首先,阐述了倍增的概念,然后详细讲解如何利用倍增求解单个点的祖先。接着,讨论了如何处理深度不同的两个节点,通过预处理和调整深度来找到它们的LCA。最后,提供了一个类封装的模板作为实现示例。
摘要由CSDN通过智能技术生成

LCA 倍增法

这里是求树上两点最近公共祖先的倍增求法。

倍增

简单来说,倍增就是:
1 , 2 , 4 , 8 , 16 , 32 , ⋯ 1,2,4,8,16,32,\cdots 1,2,4,8,16,32,
像上面这个数列(其实准确来讲应该是思维),任何大于0的正整数,它都能够表示,这就是倍增。

倍增求LCA

这个点的祖先

不考虑如何求得那个祖先。考虑这个结点到祖先节点的路径,发现使用上面的倍增方法可以很好的描述(因为上面那个玩意可以很好的表达出这条路径长度嘛)。

考虑从小到大去表示这条路径,会发现很难描述用上面的方法如何去描述,但是从大到小去描述反而很简单(这个问题就像要求一个十进制的数字转化为二进制,方法是1248那样转化,是从小到大枚举可能的位置简单呢,还是从大到小枚举位置简单呢)。

因此,已经找到了一种快速找到这个结点的任意一个祖先的方法。

但是求两个点的祖先呢?

找两个结点的最近公共祖先

考虑两个深度一样的结点。如果我们可以按上面那种方式一起跳,不就可以一起遇到了嘛。然后这个问题就解决了。

但是更多的问题是两个结点深度不同。那想个法子把深度大的结点的深度缩一缩不久可以了嘛(当然如果有人愿意让那个深度小的结点跳到大的的话,也行(虽然可能还没到,这棵树就不够深了))。

问题又来了,我要怎么知道按那个数列的祖先呢?

即答:预处理呗(其实就是递推一下就好了)。具体如下。

vector<vector<int>>g;
const int MAXN = 1e6 + 10;
// 虽然这里是lg,但实际上是log2的预处理数组,具体为什么是log2看看上面那个数列化为2的指数形式
// fa数组的31个够多了,除非这棵树真的大(2^31不很大吗)
int fa[MAXN][31], depth[MAXN], lg[MAXN];
int n;  //这颗树的结点数量

inline void pre() {
   
    // 当然也可以用std::log2()函数,就是很慢
    lg[1] = 0, lg[2] = 1;
    for (int i = 3; i <= n; ++ i)
        lg[i] = lg[i >> 1] + 1;
}
// 这里是预处理祖先
void dfs(int now, int dad
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值