一、算法定义
LCA是在线查询树上两点的最近公共祖先的算法,可运用倍增的方法,时间复杂组O(nlogn)
二、算法过程
1.倍增使深度较深的点跳到和深度较浅的点同一深度。
2.两个点一起往上跳,直到找到公共祖先
三、模板
//预处理:通过dfs,求出树上每个节点的深度。注:p[x][0]是x的父节点,如果遍历到父节点则跳过,其他的与该点相邻的点都是他的子节点
void dfs(int x)
{
for(int i=head[x];i;i=next[i]){
int go=to[i];
if(go==p[x][0]) continue;
d[go]=d[x]+1;
dis[go]=dis[x]+len[i];
p[go][0]=x;
dfs(go);
}
}
//处理处树上各个节点的u上的2^i的祖先p[u][i];
void init()
{
for(int j=1;(1<<j)<=n;j++){
for(int i=1;i<=n;i++)
p[i][j]=p[p[i][j-1]][j-1];
}
}
//找出查询点a和b中较深的一个点,使其和较浅的一个点达到相同深度
int lca(int a,int b)
{
if(d[a]>d[b]) swap(a,b);
f=d[b]-d[a];//两者相差的深度
for(int i=0;(1<<i)<=f;i++){//(1<<i)&f找到f化为2进制后1的位置,移动到相应的位置
if((1<<i)&f) b=p[b][i];
}
//a,b两个点一起倍增向上跳,直到找到公共祖先,这个祖先就是他们的最近公共祖先(a,b每次跳都将自身更新成现在已经跳到的祖先)
if(a!=b){
for(int i=log2(n);i>=0;i--){
if(p[a][i]!=p[b][i]){
a=p[a][i]; b=p[b][i];//更新a,b
}
}
a=p[a][0];
}
return a;
}
参考文章:blog.youkuaiyun.com/spencer12138/article/details/78483685