LCA 问题解法(Least Common Ancestor)

LCA = Least Common Ancestor

1. 倍增

先确定一点为根。
预处理出f[i][j], 表示从i开始往上跳2j,所到达的节点编号。

对于求解ab的LCA:(假设其LCA为节点c, c的儿子节点为k
我们先让它们跳到同一高度。
然后应注意这几个事实:abk所需要跳的长度len是相等的。也就是说存在一个唯一的len的二进制分解;2i>2i1+2i2+...+20
接下来要做的是从大到小枚举2的次幂,对于2i, 如果ab往上跳2i不相等,那就让ab往上跳2i,即len的二进制分解后第i位为1

2. 将树上 LCA 转化为序列 RMQ(Range Minimum/Maximum Query)

2.0 定义

欧拉序列:上面这棵树所对应的欧拉序列为:1, 5, 1, 4, 3, 4, 2, 4, 1
dfs 序:1 5 4 3 2。后文用 Di 代替 dfs 序中的第 i 项。
dfn:dfn1=1,dfn5=2,dfn4=3,dfn3=4,dfn2=5
posi : 节点 i 在欧拉序列中第一次出现的位置。如,pos4=4
LCA(a,b)a,b 的 LCA 的节点编号。

2.1 dfs 序

  • 一个事实:遍历以 x 为根的子树:xx 的子树1 — x 的子树2... || 在 dfs 序中,x 的后代一定在 x 之后。

  • 算法分析

问题:对于 u,v, 求 LCA(u,v)u=v 特判。

不妨设 dfnu<dfnv,即先遍历到 u

u,v 不为祖孙关系时,即 LCA(u,v)u
D[dfn[u]...dfn[v]] 中/深度最小的节点/的父亲是 LCA(u,v)。(※)

uv 的祖先,我们想要沿用 ① 的方法(※),希望它能推广到这种情况。
D[dfn[u]+1...dfn[v]] 中/深度最小的节点/的父亲是 LCA(u,v)
事实上,我们发现这个对于 ① 的情况也适用。(※)

综上,对于 dfnu<dfnvD[dfn[u]+1...dfn[v]] 中/深度最小的节点/的父亲是 LCA(u,v)

2.2 欧拉序

  • 算法过程:

对于给定的有根树 T, 求出其欧拉序列 F
现在想要求节点 a,b 的 LCA。
不妨设 posa<=posb
有结论: 设 Fk 的深度是 F[posa...posb] 中深度最小的节点,节点 a,b 的 LCA 就是 Fk

  • 正确性说明:

首先,F[posa...posb] 中有 LCA(a,b)
其次,F[posa...posb] 中深度最小的节点有且仅有一个。
最后,LCA(a,b)F[posa...posb] 中深度最小的节点。

posted @   Jiayn  阅读(62)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示