[知识点]最近公共祖先LCA
UPDATE(20180822):重写部分代码。
1、前言
最近公共祖先(LCA),作为树上问题,应用非常广泛,而求解的方式也非常多,复杂度各有不同,这里对几种常用的方法汇一下总。
2、基本概念和暴力算法
最近公共祖先,顾名思义,指的是两个点的公有祖先中,最近的那个点。它显然不会作为一个单独的知识点拿出来考,但是在很多题目中,出现的频率很高,不同场合用不同的方法。先考虑最简单的做法。找祖先,显然是从所查询的两个点从下往上爬,直到两个点出现第一次重叠时,就是最近公共祖先了。首先我们预处理出所有点的深度及父亲节点。由于两个点深度可能不同,首先我们要保证深度大的点先往上爬到与另一个点深度相同的地方,然后两个点同时向上爬,直到出现重叠。代码如下:
int lca_n() {
if (d[x] < d[y]) swap(x, y);
while (d[x] != d[y]) x = fa[x];
while (x != y) x = fa[x], y = fa[y];
return x;
}
3、倍增LCA
倍增这个概念听名字很好理解,知道倍增思想的,直接运用到求LCA并不是不好理解。首先我们需要预处理出所有节点的各种祖宗关系,p[i][j]记录节点i的第2^j个祖先,j = 0时,就是他的父亲节点。同上述暴力算法,我们从询问的两个点开始,往他们的这些倍数祖先向上爬,若第2^i个祖先不同,则从第2^(i - 1)个祖先开始,从头开始倍增。时间复杂度为 log 级别。代码如下:
void prep() {
for (int i = ; i <= n; i++) p[i][] = fa[i];
for (int j = ; ( << j) <= n; j++)
for (int i = ; i <= n; i++)
if (p[i][j - ]) p[i][j] = p[p[i][j - ]][j - ];
}
int lca_h() {
if (d[x] < d[y]) swap(x, y);
while (d[x] != d[y]) {
int o = ;
while (d[p[x][o]] > d[y]) o++;
x = p[x][o - ];
}
while (x != y) {
int o = ;
while (p[x][o] != p[y][o]) o++;
x = p[x][o - ], y = p[y][o - ];
}
return x;
}
4、树链剖分LCA
树链剖分详细概念见(http://www.cnblogs.com/jinkun113/p/4683299.html)。为什么树链剖分可以跑LCA?原文提得很清楚,在把重链划分出来之后,可以确定的是重链要么单独一条存在,要么必定相连,故可以用线段树来维护。
树链剖分的优势和倍增是一样的,都可以跳过一些不必要的部分,若当前点的重链顶端不是父亲节点,可以利用线段树直接从当前点跳到顶端。这样可以达到减小复杂度的目的。
这里写出树链剖分DFS预处理和LCA核心代码的最新版本。代码到树链剖分那篇文章中找吧。
5、Tarjan LCA
(暂略)
[知识点]最近公共祖先LCA的更多相关文章
- Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集)
Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集) Description sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为 ...
- POJ 1470 Closest Common Ancestors(最近公共祖先 LCA)
POJ 1470 Closest Common Ancestors(最近公共祖先 LCA) Description Write a program that takes as input a root ...
- POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA)
POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA) Description A ...
- [模板] 最近公共祖先/lca
简介 最近公共祖先 \(lca(a,b)\) 指的是a到根的路径和b到n的路径的深度最大的公共点. 定理. 以 \(r\) 为根的树上的路径 \((a,b) = (r,a) + (r,b) - 2 * ...
- 【lhyaaa】最近公共祖先LCA——倍增!!!
高级的算法——倍增!!! 根据LCA的定义,我们可以知道假如有两个节点x和y,则LCA(x,y)是 x 到根的路 径与 y 到根的路径的交汇点,同时也是 x 和 y 之间所有路径中深度最小的节 点,所 ...
- POJ 1470 Closest Common Ancestors (最近公共祖先LCA 的离线算法Tarjan)
Tarjan算法的详细介绍,请戳: http://www.cnblogs.com/chenxiwenruo/p/3529533.html #include <iostream> #incl ...
- 【Leetcode】查找二叉树中任意结点的最近公共祖先(LCA问题)
寻找最近公共祖先,示例如下: 1 / \ 2 3 / \ / \ 4 5 6 7 / \ ...
- 最近公共祖先LCA(Tarjan算法)的思考和算法实现
LCA 最近公共祖先 Tarjan(离线)算法的基本思路及其算法实现 小广告:METO CODE 安溪一中信息学在线评测系统(OJ) //由于这是第一篇博客..有点瑕疵...比如我把false写成了f ...
- 查找最近公共祖先(LCA)
一.问题 求有根树的任意两个节点的最近公共祖先(一般来说都是指二叉树).最近公共祖先简称LCA(Lowest Common Ancestor).例如,如下图一棵普通的二叉树. 结点3和结点4的最近公共 ...
随机推荐
- 06Shell并发控制
并发控制 文件描述 文件句柄 File Descriptors (FD,文件描述符)或 文件句柄: 进程使用文件描述符来管理打开的文件 注意 1.如何通过exec打开一个文件 exec 数字<& ...
- 简明了解apply()和call()
apply()和call()都是ES6语法的,并且都是函数的方法. function foo() { alert(this.name) } var obj = { name: '小明' } foo() ...
- vue怎么给自定义组件绑定原生事件
下面主要以4个示例Demo演示(示例代码JS引用的Vue CDN),建议小伙伴直接复制示例代码运行查看, 赶时间的小伙伴可直接往下拉,看示例demo4 注:全局或局部注册的组件称为子组件,其中声明的 ...
- javascript的数据类型检测
JavaScript有两种数据类型,分别是基本数据类型和引用数据类型.其中基本数据类型包括Undefined.Null.Boolean.Number.String和Symbol(ES6新增,表示独一无 ...
- Winform中设置ZedGraph鼠标滚轮缩放的灵敏度以及设置滚轮缩放的方式(鼠标焦点为中心还是图形中心点)
场景 Winforn中设置ZedGraph曲线图的属性.坐标轴属性.刻度属性: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/10 ...
- Winform中对DevExpress的RadopGroup的Description、Value、Tag、Text的理解与使用
场景 Winform中实现读取xml配置文件并动态配置ZedGraph的RadioGroup的选项: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article ...
- mvc后台传到前台的值带html标签css(解决方法)
mvc后台传到前台的值带html标签css MVC中要用:@Html.Raw(后台数据库取的值); 或者MvcHtmlString.create();
- vue.js 父组件主动获取子组件的数据和方法、子组件主动获取父组件的数据和方法
父组件主动获取子组件的数据和方法 1.调用子组件的时候 定义一个ref <headerchild ref="headerChild"></headerchild& ...
- Linux 和 Windows多线程函数对应表
Linux Pthread API Windows SDK 库对应 API 创建 pthread_create CreateThread 退出 pthread_exit ThreadExit 等待 p ...
- ios路线
http://www.cocoachina.com/ios/20150303/11218.html