写在前面
本蒟蒻晚上闲得无聊,随便写写,感谢大家的观看
有错误请多多指出
正文
本文讲解如何使用 tarjan算法 求LCA
tarjan算法是一种 离线 算法
目的
首先了解一下 LCA
LCA(Least Common
Ancestors),即最近公共祖先,是指这样一个问题:在有根树中,找出某两个结点u和v最近的公共祖先(另一种说法,离树根最远的公共祖先)
举个简单的例子
给大家一张图理解一下
一个 节点的祖先 可以是他的 父亲 也可以是他 自己
故图中
节点4 和 节点6 的最近公共祖先是 节点2
节点5 和 节点6 的最近公共祖先是 节点5
节点4 和 节点3 的最近公共祖先是 节点1
节点5 和 节点3 的最近公共祖先是 节点1
朴素算法
直接 暴力搜索 即可
求 节点A 和 节点B 的最近公共祖先
1.从 节点A 到 根节点,途中的 每个节点 标记 1
2.从 节点B 到 根节点,途中的遇到 第一个标记为1的点 就是最近公共祖先
实现较为简单,在此不多做阐述
下面开始讲解 tarjan算法
流程
需要了解 并查集
tarjan算法的具体流程如下
1.存储询问
由于是 离线算法
第一步需要存储询问
一般由于空间的要求使用 邻接表 + pair 存储,反正我用的是
2.遍历
从根节点向下遍历,遇到一个 未访问过的点 标记为 1
如果遇到 叶子结点 将当前 未访问过的点 与 当前点 合并(此处并查集数组为 pre)然后看看当前节点是否有询问,没有询问直接将此结点标记为 2, 回溯
一直到
这时我们发现 节点6 和 节点4 有询问
如果遇到 叶子结点 并且与 其他节点 有询问,如果 其他节点 的标记为 2,则这两个节点的 最近公共祖先 为 其他节点 并查集的祖先
接着遍历即可
代码
代码的实现也相对简单
1.定义
前向星等基础操作,pre 是 并查集 的数组,ans 数组 标记答案,vis 数组 是当前节点的 标记
using namespace std;