LCA-倍增法找最近公共祖先

该篇文章介绍了如何在给定的有根多叉树中,利用深度优先搜索和层次关系计算任意两个节点的最近公共祖先,通过构建倍增模板实现高效查询。
摘要由CSDN通过智能技术生成

如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。

输入格式:
第一行包含三个正整数N , M , S N,M,SN,M,S,分别表示树的结点个数、询问的个数和树根结点的序号。接下来N − 1 N-1N−1行每行包含两个正整数x , y x,yx,y,表示x xx结点和y yy结点之间有一条直接连接的边(数据保证可以构成树)。接下来M MM行每行包含两个正整数a , b a,ba,b,表示询问a aa结点和b bb结点的最近公共祖先。

输出格式:
输出包含M MM行,每行包含一个正整数,依次为每一个询问的结果。

#include <iostream>
using namespace std;
const int N = 10010;
struct Eage {
	int to;
	int next;
}edge[2*N];
int head[2 * N];
int deep[N];
int fa[N][20];
int cnt;

void init()
{ 
	for (int i = 0; i < 2 * N; i++)   //初始化链式向前星
	{
		head[i] = -1;
		edge[i].next = -1;
		
   }
	cnt = 0;
}
void addEage(int u, int v)
{
	edge[cnt].to = v; edge[cnt].next = head[u]; head[u] = cnt++;   //添加链式向前星
}
void dfs(int x,int father)    //建立倍数跳跃模板
{
	deep[x] = deep[father] + 1;
	fa[x][0] = father;
	for (int i = 1; (1 << i) <= deep[x]; i++)   //倍增的模板,最远不能跳过根节点
	{
		fa[x][i] = fa[fa[x][i - 1]][i - 1];
	}
	for (int i = head[x]; i!=-1; i=edge[i].next)
	{
		if (edge[i].to != father)
			dfs(edge[i].to, x);
	}
}
int LCA(int x,int y)
{
	if (deep[x] < deep[y]) { swap(x, y); }
	for (int i = 19; i >= 0; i--)
	{
		if (deep[x] - (1 << i) >= deep[y])
			x = fa[x][i];
	}
	if (x == y) return y;
	for (int i = 19; i >= 0; i--)
	{                    
		
		if (fa[x][i] != fa[y][i])           //x和y相等会继续跳到最后一次相等为止

	     //if(x!=y) 一直相等 
		{
			x = fa[x][i];
			y = fa[y][i];
		}
		}
	return x;
}
void solve()
{
	init();
	int n, m, root;
	cin >> n >> m >> root;
	for (int i = 1; i < n; i++)
	{
		int u, v;
		cin >> u >> v;
		addEage(u, v);
		addEage(v, u);
	}
	dfs(root, 0);
	while (m--)
	{
		int a, b;
		cin >> a >> b;
		cout<< LCA(a, b) << endl;
	}

}
unsigned main()
{
	ios::sync_with_stdio(false);
	int num = 1;
	while (num--)
	{
		solve();
	}
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值