【手敲算法】LCA (最近公共祖先) 从理解 到 裸敲

本文介绍了最近公共祖先(LCA)算法的重要性,并详细讲解了三种不同的LCA算法:Tarjan算法、DFS+ST(RMQ)算法和倍增法。通过这些算法,可以高效地在树形结构中查找两个节点的最近公共祖先。文章提供了每种算法的原理和代码实现,并特别强调了在处理大规模数据时需要注意的优化技巧,如使用链式前向星代替vector建图。
摘要由CSDN通过智能技术生成

注:代码经过简单修改即可适用于 洛谷P3379

代码洛谷题目范围 为 n = 5e5,以下代码内部使用的 vector push_back 和 遍历 vector 导致本题部分代码 Time Limit

可以使用如下代码替换 add建边,和 循环

int cnt = -1, head[maxn];
struct node{
    int nxt, to;
};
node Edge[maxn*2];
void add(int u,int v){
	Edge[++cnt].nxt = head[u];
	Edge[cnt].to = v;
	head[u] = cnt;
}

// 主程序内需要初始化
	memset(head, -1, sizeof(head));
	for(int i=head[u];i!=-1;i=Edge[i].nxt){
		int v = Edge[i].to;
    }

 

为什么要学习LCA算法

LCA :两个树上节点,逐层向上寻找它们的父节点,第一次查找到的 "相同 (祖先) 节点"

查询q次,每次给出两个节点,向上递归查找,最坏情况下是 O(n* q) 的时间复杂度
要降低查询的时间复杂度


共有三种算法:(在线:来一个查询操作,执行一次query;离线:读入全部查询操作,一次性计算所有结果)

1. LCA tarjan算法                O(n +q)       离线算法
2. dfs + ST(RMQ) 算法        O(n * logn) 在线算法, RMQ预处理后可以做到  O(1) 查询
3. 倍增算法                           O(n * logn) 在线算法,O(n * logn)处理数据,O(logn)查询

  • 算法一:LCA tarjan算法

算法原理

dfs 过程:

1.  查询当前  节点u,是否包含未遍历  子节点v,包含继续向下递归查找,回溯时 更新 节点v的 fa[v] = u
2.  遍历完当前节点所有子树,
     在查询集合中,查找是否在  在包括当前节点u  的所有查询中:
         如果这个查询(u , v)的另一个节点v  被遍历过,那么当前这个查询(u, v)的答案是   v节点所在并查集里的根节点


如上图 查询 (8 , 11) 的 LCA,因为2号节点 的 fa[2] 并未更新,还是初始值 2 ,
依次查到 5节点,10节点 11节点时,将它们放入绿框内,(fa[2] = 2不变,
之前所有绿框内的 节点,根据并查集,都会维护在2号节点下,他们所属并查集的根节点 为2
查到11节点,这个查询(8 , 11

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值