目录
一:定义
在OI Kiki上是这么说的
最近公共祖先简称 LCA(Lowest Common Ancestor)。两个节点的最近公共祖先,就是这两个点的公共祖先里面,离根最远的那个(也就是离两个点最近的那个)。
二:实现
壹:暴力
1.标记法
可以先让一个点一直往上跳到根节点,然后每次给跳到的点打上标记(初始点要打)
最后从另一个点也往上跳,如果这个点有标记就输出
2.跳跃法(1)
每次让深度比较大的那个点向上跳,如果两个点相遇了,就输出
3.跳跃法(2)
先让深度较大的点一直跳到与另一个点深度相同,然后再共同向上跳,如果两个点重回,就输出
4.注意
两个跳跃法都需要先预处理出深度
贰:倍增法
大家可以先看看我的这篇博客学习一下RMQ,这里也是用差不多的方法
我们现设ans[i][j]表示从i点往上走步走到的点
那么ans[i][j] = ans[ans[i][j-1][j-1]
ans[i][0]就等于i的父亲节点
接着,我们可以运用我之前讲的跳跃法(2)来进行寻找,最后输出就行了
这里放上代码
vector<int> a[114514];//作者这里使用vector来存树
int b[114514];//每个点的深度
inn ans[114514][22];//跳跃到点
void dfs(int x,int fa,int sum){//用来求深度(根节点的深度为一)
b[x] = sum;
for(int i=0;i<a[x].size();i++){
int y = a[x][i];
if(y==fa) continue;
ans[y][0] = x;
dfs(y,x,sum+1);
}
}
int lca(int x,int y){//跳跃法
if(b[x]<b[y]) swap(x,y);//找出深度小的点
for(int i=20;i>=0;i--) if(b[ans[x][i]]>=b[y]) x = ans[x][i];//不断进行调整
if(x==y) return x;//如果两个点在同一个点了(原本在一颗子树)就输出
for(int i=20;i>=0;i--) if(ans[x][i]!=ans[y][i]) x = ans[x][i],y = ans[y][i];//同步进行跳跃
return ans[x][0];//最后输出
}
三:结语
如果这篇文章对您有帮助的话,请记得点赞收藏加关注吖~