最近公共祖先

0. 概要



最近公共祖先,指的是在一颗有根树上,两个点的公共祖先中,深度最大的那个。

最直接的应用是求无权树上两个点的最短距离:$distance(u, v)  = depth(u) + depth(v) - 2depth(lca(u, v))$。

再有其他的应用则以后再提。

1 基于 dfs 序列上 RMQ 的稀疏表解法



首先 dfs 遍历树,如下如图中蓝色箭头的顺序。并记录:

  1. 遍历点序列 $euler[] = \{1, 2, 1, 3, 5, 3, 6 ……$

  2. 每个点首次在 euler 中出现的位置,$firstIn[1] = 0, firstIn[2] = 1, firstIn[3] = 3 ......$

  3. 每个点的深度,$depth[1] = 0, depth[2] = 1, depth[3] = 1, ......$

有了这些我们就可以发现两个点的 lca 其实并不难求,比如 9 和 12 的 lca 是多少?首先在 dfs 的过程中,这个点一定在 9 和 12 之间被访问了。其次,这个点是这之中访问的点中深度最小的。

所以,只要在 firstIn[9] 到 firstIn[12] 之间的 euler[] 中,找到深度最小的点就可以了。

这就转换成了一个 RMQ 问题。

因为这个 RMQ 问题不需维护更改,一般我们用稀疏表来解决。

/*

  子内容:稀疏表。

  稀疏表是一种解决 RMQ 问题的有效手段,可以做到 $O(n \log(n))$ 预处理,$O(1)$ 询问区间最小(大)值。

  具体做法是这样的。待处理的数组如果是 A[],这个时候用一个辅助数组 B[][],B[i][j] 表示 A[j] 开始,长度为 $2^i$ 的子串的最值。

  比如,B[2][4] 表示 A[4] A[5] A[6] A[7] 的最值;B[0][i] 就等于 A[i]。

  利用递推的方法可以 $O(n \log(n))$ 处理出来这个表。

  查询一个区间 [l, r] 的最值时,令 $k = log_2(r - l + 1)$,这样只需要 $B[k][l]$ 和 $B[k][r - 2^{i-1} + 1]$ 比较就可以得到结果。

*/

2. tarjan



这个是一个离线算法,需要用并查集维护。

具体介绍请看这里:http://noalgo.info/476.html 此人讲的很清楚,我就不多废话了。

此外还有倍增的方法,但是我没用过。

时间: 2024-10-16 13:22:07

最近公共祖先的相关文章

【洛谷P3379】【模板】最近公共祖先(LCA)

题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入样例#1: 5 5 4 3 1 2 4 5

50、树中两个节点的公共祖先

详细的询问: 1.该树是二叉查找树? 最近公共祖先----二叉查找树:(http://www.lintcode.com/problem/lowest-common-ancestor/) 思路:利用左子树特点:左子树 < 根 <= 右,输入节点跟根节点比较,都小于,在左子树,都大约右子树,递归的去遍历:找到当前节点在两个输入大小之间,当前节点就是. 递归和非递归 public class Solution { public TreeNode lowestCommonAncestor(TreeNo

[最近公共祖先] POJ 3728 The merchant

The merchant Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 4556   Accepted: 1576 Description There are N cities in a country, and there is one and only one simple path between each pair of cities. A merchant has chosen some paths and w

lca最近公共祖先(st表)

大体思路 1.求出每个元素在树中的深度 2.用st表预处理的方法处理出f[i][j],f[i][j]表示元素i上方第2^j行对应的祖先是谁 3.将较深的点向上挪,直到两结点的深度相同 4.深度相同后,祖先可能就在上方,再走几步就到了,于是两个点同时向上移 具体的方法和代码贴在下面 ↓ 具体来看 1.求出每个元素在树中的深度 //求每个节点在树中的深度 void dfs(int pos,int pre)//pre是pos的父节点 { for(int i=0;i<v[pos].size;i++)//

LCA(最近公共祖先)--tarjan离线算法 hdu 2586

HDU 2586 How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 11320    Accepted Submission(s): 4119 Problem Description There are n houses in the village and some bidirectional roads c

最近公共祖先 LCA Tarjan算法

来自:http://www.cnblogs.com/ylfdrib/archive/2010/11/03/1867901.html 对于一棵有根树,就会有父亲结点,祖先结点,当然最近公共祖先就是这两个点所有的祖先结点中深度最大的一个结点. 0 | 1 /   \ 2      3 比如说在这里,如果0为根的话,那么1是2和3的父亲结点,0是1的父亲结点,0和1都是2和3的公共祖先结点,但是1才是最近的公共祖先结点,或者说1是2和3的所有祖先结点中距离根结点最远的祖先结点. 在求解最近公共祖先为问

LeetCode OJ:Lowest Common Ancestor of a Binary Tree(最近公共祖先)

Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w

最近公共祖先(三种算法)

最近研究了一下最近公共祖先算法,根据效率和实现方式不同可以分为基本算法.在线算法和离线算法.下面将结合hihocoder上的题目分别讲解这三种算法. 1.基本算法 对于最近公共祖先问题,最容易想到的算法就是从根开始遍历到两个查询的节点,然后记录下这两条路径,两条路径中距离根节点最远的节点就是所要求的公共祖先. 题目参见 #1062 : 最近公共祖先·一 附上AC代码,由于记录的方式采取的是儿子对应父亲,所以实现的时候有点小技巧,就是对第一个节点的路径进行标记,查找第二个节点的路径时一旦发现访问到

HDU2586 How far away ?【最近公共祖先】【Tarjan-LCA算法】

How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 6252    Accepted Submission(s): 2344 Problem Description There are n houses in the village and some bidirectional roads connecting