C++最近公共祖先(LCA版)
问题描述
给出一棵有N(编号1到N)个节点的有根树,求出指定节点对的最近公共祖先!
对于树中节点x而言,从根节点到达x的这一条路径中经过的所有节点,都称为x的祖先。
如上图所表示的树中, 根节点为8。8、4、10、16都是12的祖先。对于6和12这对节点而言,从6出发往上朝根走和从12出发往上朝根走的两条路径最早交汇的地点是4号节点,因此4号点是6和12的最近公共祖先。
同理,11和9的最近公共祖先是8; 10和3的最近公共祖先是10;2和7的最近公共祖先是4…
输入格式
第一行,一个整数N。表示树中节点总数
接下来N-1行,每行两个整数x和y,表示x是y的父亲。
接下来一行,一个整数M,表示询问的总数
接下来M行,每行两个整数a和b,表示询问a和b的最近公共祖先。
输出格式
M行,每行一个整数,表示对应询问的答案。
大概思路: 用dep[]来标记树的深度,fa[v][k]来标记v点向上2^k
步骤:1.DFS来确定层数,将x,y移到同一水平线;
2.将x,y同时向上移,如果x==y就return x;
不说了,直接看代码
代码:
#include<bits/stdc++.h>
using namespace std;
int Last[10010],Next[10010],End[10010],n,m,x,y,z,Dep[10010],Fa[10010][10010];
void Dfs(int x){
int i,k,y;
Dep[x]=Dep[Fa[x][0]]+1;
k=ceil(log2(Dep[x]));
for(i=1;i<=k;i++){
Fa[x][i]=Fa[Fa[x][i-1]][i-1];
}
i=Last[x];
while(i){
y=End[i];
Dfs(y);
i=Next[i];
}
}
int LCA(int u,int v)
{
int i,k,s;
s=ceil(log2(n));
if(Dep[u]<Dep[v])swap(u,v);
for(i=s;i>=0;i--)
{
if(Dep[Fa[u][i]]>=Dep[v])
u=Fa[u][i];
if(u==v)
return u;
}
s=ceil(log2(Dep[u]));
for(i=s;i>=0;i--)
{
if(Fa[u][i]!=Fa[v][i])
{
u=Fa[u][i];
v=Fa[v][i];
}
}
return Fa[u][0];//最近公共祖先的上面的结点都是公共祖先
}
int main()
{
scanf("%d",&n,&m);
for(int i=1;i<n;i++){
scanf("%d %d %d",&x,&y,&z);
Fa[y][0]=x;//建边
End[i]=y;
Next[i]=Last[x];
Last[x]=i;
}
for(int i=1;i<=n;i++){
if(Fa[i][0]==0){
Dfs(i);
break;
}
}
for(int i=1;i<=m;i++){
scanf("%d %d",&x,&y);
printf("%d\n",LCA(x,y));
}
return 0;
}
好啦,差不多就是这样啦,ღ( ´・ᴗ・` )比心 ~
来源:CSDN
作者:CPGhanyue
链接:https://blog.csdn.net/CPGhanyue/article/details/104676753