C++最近公共祖先(LCA版)

百般思念 提交于 2020-03-05 20:34:05

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;
}

好啦,差不多就是这样啦,ღ( ´・ᴗ・` )比心 ~
在这里插入图片描述

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!