倍增法求LCA
来源:互联网 发布:养匪自重知乎 编辑:程序博客网 时间:2024/04/30 21:53
何为LCA
就像节目开始之前主持人总要念段广告一样,在这里我要先介绍何为LCA
LCA(Least Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先。
倍增法
顾名思义,取“成倍地增加”之义
引入倍增法往往可以将O(n)进化为O(log(n))
倍增法求LCA
注意:请务必搭配手动模拟食用
初始化
分两步
- 深搜遍历树,更新每个点的深度
- 然后用f[i][j]记录点i的第2^j次幂的祖先是谁
更新f[i][j]数组代码如下
void pre(){ maxh=log(n)/log(2)//以2为低n的对数(换底公式可证) for(int j=1;j<=maxh;j++) for(int i=1;i<=N;i++) fa[i][j]=fa[fa[i][j-1]][j-1]; }
具体来讲,更新的思路是:i的第
需要注意的是,外层循环j代表2的j次幂,这样的话,就可以保证 i的第
求LCA
求LCA大抵分两步
- 调平
- 求LCA
调平是指将所求两点调到相同深度
因为要保证LCA算法整体复杂度在O(log(n))水平,因此一般的方法(O(n)+)是不可行的
所以在此介绍倍增的调平办法
先放代码
if(deep[x]<deep[y]) swap(x,y);//保证x的深度大于y的深度 int d=deep[x]-deep[y]; for(int i=0;i<=maxh;i++){ if((1<<i)&d) x=fa[x][i]; }
这个式子需要详细说明一下:
- 首先是位运算,不懂的同学建议详细学一下,很神奇的,由于本人讲不清楚故不再赘述
- 从度娘百科回来的你不难发现“&”符可以用来2进制分解;而
(1<<i) 则等价于2i ——这样一切的一切就越发清晰了:该循环的目的是对d二进制分解,并在分解的途中让x向上跳
LCA剩下的代码是这样的
if(x==y) return x;//如果调平之后x、y重合,则y即为所求 for(int j=maxh;j>=0;j--){ if(fa[x][j]!=fa[y][j]){ x=fa[x][j]; y=fa[y][j]; } } return fa[x][0];
如果最大距离时两点祖先相同,则LCA必然在两点和最大距离之间(废话)
但是在从最远向近处跳的同时我们也在缩小LCA可能存在的区间上限
当跳到某深度,x、y的祖先不是一个了,就将x、y跳到该深度(缩短下限)
由于区间每次都缩小一半,所以该for复杂度为O(log(n))
值得注意的是,x、y最后会停在LCA的儿子上,所以他们的父亲就是我们苦苦寻找的LCA
强烈建议画图模拟~
举个例子~
阅读全文
0 0
- 倍增法求LCA
- 倍增法求LCA
- 倍增法求LCA
- 倍增法求LCA
- 倍增法求 LCA
- 倍增法求LCA
- 浅谈倍增法求LCA
- 倍增法求LCA模版
- 倍增法求lca 模板
- 树上倍增法求LCA
- 倍增法求lca模板
- 【模板】倍增法求lca
- POJ1470 倍增法在线求LCA
- 倍增法求LCA的模板
- 倍增法求最近公共祖先 lca
- Pascal 倍增求LCA
- 树上倍增求LCA
- 【LCA】倍增法 LCA
- Android样式的开发
- Xcode9学习笔记36
- 配置Eclipse编写HTML/JS/CSS/JSP页面的自动提示
- 我们计划为EasyDSS定制开发一款超低延时的EasyPlayer Flash播放器
- WIN10下安装MYSQL5.5.55时最后出现“mysql server instance configuration wizard未响应”
- 倍增法求LCA
- IntelliJ IDEA中文乱码问题
- Xcode9学习笔记37
- 「Deep Learning」Caffe: convert_imageset.cpp
- 二分总结
- 使用https加密之后的数据问题
- 宏基因组实战5. sourmash基于Kmer比较数据集
- 接续符
- 二分的各种操作