浅谈倍增查找LCA
来源:互联网 发布:sql 查询月份 编辑:程序博客网 时间:2024/06/06 09:09
- 前言
- LCA是什么
- 如何实现LCA
- LCA模板题
- 题目描述 Description
- 输入描述 Input Description
- 输出描述 Output Description
- 样例输入 Sample Input
- 样例输出 Sample Output
- 数据范围及提示 Data Size Hint
前言
这篇文章,是一篇总结倍增查找LCA的一篇文章,同时也是实现在浅谈RMQ算法文章中承诺.若有疑问或建议,请于下方留言,谢谢!
LCA是什么?
LCA(Least Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先
如何实现LCA?
- 暴力直接找
- 首先将u,v中深度较深的那个点蹦到和较浅的点同样的深度
- 然后两个点一起向上蹦直到蹦到同一个点,这个点就是它们的LCA
- 时间复杂度在极端条件下可以到O(N)
- 运用DFS序
- DFS序就是用DFS方法遍历整棵树得到的序列。
- 两个点的LCA一定是两个点在DFS序中出现的位置之间深度最小的那个点
- 寻找最小值可以用使用我们前篇文章讲的RMQ
- 运用倍增思想
- 我们令father[i][j]表示编号为i的点,往上蹦2^j次的父亲是谁,其实这个预处理和RMQ很相似,先从大到小枚举j,然后令father[i][j]=father[father[i][j-1]][j-1],这样预处理的时间复杂度为O(NlogN)
- 接下来是查询,可以分两步走
- 将u和v移动到同样的深度
- u和v同时向上移动,直到重合。第一个重合的点即为LCA
- 再是移动到同样的深度
- 令u为深度较大的点。我们从
log2n , 到0枚举,令枚举的数字为j。如果从u向上跳2j 步小于了v的深度,不动;否则向上跳2j 步。这样一定能移动到和v一样的深度。 - 假设一共要跳k步,上面的算法相当于枚举k的每个2进制为是0还是1
- 令u为深度较大的点。我们从
- 从同样的深度移动到同一个点
- 和上一步类似。从
log2n 到0枚举,令枚举的数字为j。如果两个向上跳2j 步将要重合,不动,否则向上跳2j 步。 - 通过这种办法u和v一定能够到达这样一种状态——它们当前不重合,如果再向上一步就重合。所以再上一步就得到了LCA
- 和上一步类似。从
- 由于本质上是枚举每一个二进制位,所以单次查询的复杂度为
log2n
我们可以注意到,在整个倍增查找LCA的过程中,从u到v的整条路径都被扫描了一遍。如果我们在倍增数组F[i][j]中再记录一些别的信息,就可以实现树路径信息的维护和查询
LCA模板题
这里给一个LCA用倍增思想的模板,题目来源codevs4605 (传送门)
题目描述 Description
顾名思义.给一棵有根树,以及一些询问,每次询问树上的2 个节点A、B,求它们的最近公共祖先.
输入描述 Input Description
第一行一个整数N.
接下来N 个数,第i 个数Fi 表示i 的父亲是Fi. 若Fi = 0,则i 为树根.
接下来一个整数M.
接下来M 行,每行2 个整数A、B,询问节点(A xor LastAns)、(Bxor LastAns)的最近公共祖先. 其中LastAns 为上一个询问的答案,一开始LastAns = 0.
输出描述 Output Description
对每一个询问输出相应的答案.
样例输入 Sample Input
10
0 1 2 3 2 4 2 5 4 9
10
3 9
2 7
7 8
1 1
0 6
6 11
6 3
10 7
2 15
7 7
样例输出 Sample Output
3
1
4
5
2
4
2
5
2
5
数据范围及提示 Data Size & Hint
30% n,m≤1000
100% n,m≤100,000
代码
不解释了吧,上代码
#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<cstring>#include<queue>#include<vector>using namespace std;int n,m;vector <int> a[100001];int f[100001][18];int father[100001];int root;int height[100001];int lca(int x,int y){ if(height[x]<height[y]) { int tt=x; x=y; y=tt; } int t=0; while((1<<t) <= height[x])t++; t--; int i; for(i=t;i>=0;i--) { if(height[x]-(1<<i)>=height[y]) { x=f[x][i]; } } if(x==y)return x; for(i=t;i>=0;i--) { if(f[x][i]!=f[y][i]) { x=f[x][i]; y=f[y][i]; } } return f[x][0]; }void dfs(int x,int deep){ int i,j; height[x]=deep; for(i=1;i<=17;i++) { f[x][i]=f[f[x][i-1]][i-1]; } for(i=0;i<a[x].size();i++) { dfs(a[x][i],deep+1); }}int main(){ scanf("%d",&n); int i,j; for(i=1;i<=n;i++) { scanf("%d",&father[i]); f[i][0]=father[i]; if(f[i][0]==0) { root=i; } a[father[i]].push_back(i); } dfs(root,0); scanf("%d",&m); int ans=0; int x,y; for(i=1;i<=m;i++) { scanf("%d%d",&x,&y); x=x^ans;y=y^ans; ans=lca(x,y); printf("%d\n",ans); } return 0; }
0 0
- 浅谈倍增查找LCA
- 浅谈倍增法求LCA
- lca倍增
- lca(倍增)
- 倍增LCA
- 倍增lca
- LCA倍增
- LCA(倍增)
- 倍增 LCA
- 【LCA】倍增法 LCA
- LCA倍增算法(模板)
- HDU 4547 倍增LCA
- 倍增lca模板
- LCA倍增法模板
- lca倍增dp
- 倍增LCA模板
- 倍增法求LCA
- lca倍增算法
- Leetcode——45Jump GameII
- 20170401-leetcode-435-Non-overlapping Intervals
- poj1006 -- 生理周期
- 【Bzoj1218】激光炸弹
- 几个下载软件的网址
- 浅谈倍增查找LCA
- C语言输入输出函数总结
- 【其他】Hexo博客(Next主题)放弃多说,接入网易云跟贴
- 设计模式
- POJ 2152 Fire
- opencv 多线程显示imshow出现图片不更新的问题
- 禁用系统关闭按钮---X
- 如何使用PYTHON操作摄像头
- C文件操作的定位