求LCA的几种方法
来源:互联网 发布:虚拟网络运营商 编辑:程序博客网 时间:2024/06/05 23:56
方法一:暴力
最容易想到的方法,固然就是暴力,即一个一个往父亲节点跳,但很明显,这样很傻.
方法二:倍增(ST)
我们考虑设
便有:
int lca(int x,int y){ if (deep[x] < deep[y]) swap(x,y); for (int i = maxer; i >= 0; i--) if (deep[f[x][i]] >= deep[y]) x = f[x][i]; if (x==y) return; for (int i = maxer; i >= 0; i--) if (f[x][i]!=f[y][i]) x = f[x][i], y = f[y][i]; return f[x][0]; //注意此时的f[x][0]才是LCA.}
方法三:Tarjan
用Tarjan求LCA,更适用于离线求多对点的LCA,可以做到
具体方法不多讲,很简单.
核心思想是记录一个
方法四:DFS序
我们需要注意,用DFS序去求LCA很简单,但是如果要求一些如区间最大最小之类的,就比较麻烦.
所以,我们在求解比较复杂的LCA问题时,还是尽量用倍增.
不过用DFS序求LCA也很简单.
我们求出一棵树的dfs序,以及每个点在dfs序中第一次出现的位置,那么两个点的LCA,就是这两个点在dfs 序中第一次出现位置的区间里深度最小的那个节点.
RMQ维护即可.
以下代码转自百度(实在找不到LCA裸题)
int tot, seq[N << 1], pos[N << 1], dep[N << 1];// dfs过程,预处理深度dep、dfs序数组seqvoid dfs(int now, int fa, int d) { pos[now] = ++tot, seq[tot] = now, dep[tot] = d; for (int i = head[now]; i; i = e[i].next) { int v = e[i].to; if (v == fa) continue; dfs(v, now, d + 1); seq[++tot] = now, dep[tot] = d; }}int anc[N << 1][20]; // anc[i][j]表示i节点向上跳2^j层对应的节点void init(int len) { for (int i = 1; i <= len; i++) anc[i][0] = i; for (int k = 1; (1 << k) <= len; k++) for (int i = 1; i + (1 << k) - 1 <= len; i++) if (dep[anc[i][k - 1]] < dep[anc[i + (1 << (k - 1))][k - 1]]) anc[i][k] = anc[i][k - 1]; else anc[i][k] = anc[i + (1 << (k - 1))][k - 1];}int rmq(int l, int r) { int k = log(r - l + 1) / log(2); return dep[anc[l][k]] < dep[anc[r + 1 - (1 << k)][k]] ? anc[l][k] : anc[r + 1 - (1 << k)][k];}int calc(int x, int y) { x = pos[x], y = pos[y]; if (x > y) swap(x, y); return seq[rmq(x, y)];}int lca(int a, int b) { dfs(root, 0, 1); // root为树根节点的编号 init(tot); return calc(a, b);}
方法五:树链剖分
一开始以为树链剖分很高级,其实,是个很简单的算法.
我们设
size[u] 表示u 的子树大小.son[u] 表示u 在一条重链中的儿子.deep[u] 表示u 的深度fa[u] 表示u 的父亲top[u] 表示u 所在重链的顶端.pos[u] 表示u 在线段树中的标号.
我们把一个根节点
u ,所连向的所有v 中size 值最大的,称为重儿子,其中(u,v) 这条边称为重边.除重边外的其它边称为轻边.
树链剖分完后的树有以下一个重要性质:
重链以及轻链都不会超过
log2n 条.证明如下:因为每次往轻边走,
size 至少减少一般,所以最多有log2n 条轻边,两条重链之间至少有一条轻边,所以至多有log2n 条重链.
pos[u] 是为了求一些类似于:- 询问一条路径和,修改一段路径和
如果只要求
LCA . 我们可以采用以下的方法:设所求
LCA 的为(u,v) .判断,如果
u,v 在同一重链上时,则深度较小的那个点为LCA.否则,如果
u,v 不在同一重链上时,则比较,如果deep[top[u]]>deep[top[v] ,我们就把u 跳到top[u] ,否则把v 跳到top[v] 如果有
top[u]==u 或者top[v]==v ,我们就跳到它的父亲.这样,当
u==v 时,即为LCA.简单证明:
- 一条重链不可能有两个分支,所以,当两个点不在同一条重链上时,跳深度较深的那个点,一定不会超过LCA,最后一次跳,也不会跳出LCA.
- 求LCA的几种方法
- 求LCA的几种方法
- 求 LCA的几种算法的实现方法模板( 例题POJ1330
- 求素数的几种方法
- 求素数的几种高效方法
- 求Fibonacci数的几种方法
- 求素数的几种方法
- 求阶乘的几种方法
- 求素数的几种方法
- 求逆序数的几种方法
- 求质数的几种方法
- 求素数的几种方法
- 求素数的几种方法
- 求最大公约数的几种方法
- 求平方根的几种方法
- 求逆序数的几种方法
- 求素数的几种高效方法
- 求平均数的几种方法
- 请求大神帮帮我!!!真心寻求帮助
- 【开启Tomcat远程调试失败】Failed to connect to remote VM.
- 屡试不爽--安装Cocoapods1.1.0最新心得及问题总结!
- mysql中explain的type的解释
- 跑PCL的tutorial的第一个例子alignment_prerejective.cpp出现错误
- 求LCA的几种方法
- Ubuntu服务器部署Django项目
- 最全USB 接口类型
- CSS(六) 设置背景颜色和背景图像
- Aspect Level Sentiment Classification with Deep Memory Network笔记
- 项目异常和解决方法【持续更新】
- C语言 利用杨辉三角进行二项式展开,返回动态一维数组
- Hadoop Streaming统计电影出现的次数
- Codeforces Round #439 C The Intriguing Obsession(dp)