ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

最近公共祖先(倍增LCA)

2022-07-21 19:01:41  阅读:172  来源: 互联网

标签:结点 fa 祖先 xx int depth LCA 倍增


题目

最近公共祖先

描述

给定一棵树,请查询结点u和v的最近公共祖先。最近公共祖先,就是两个节点在这棵树上深度最大(离根结点最远)的公共的祖先节点,结点的祖先也可以是自身。

输入

输入数据第一行为结点个数n(n<=900),接下来有n行,每行格式如下:
x m y1, y2, ... ym
表示结点x有m个孩子y1, y2, ... ym
接下来有一个正整数q(q<=100000),表示查询次数,之后有q行,每行两个正整数u和v,表示待查寻的结点编号。
树结点的编号为1~n。

输出

对每次查询,输出u和v的最近公共祖先,格式为:
u v = w
其中w表示u和v的最近公共祖先结点编号。

样例输入

5
4 0
5 3 1 4 2
1 0
2 1 3
3 0
6
1 5
1 4
4 2
2 3
1 3
4 3

样例输出

1 5 = 5
1 4 = 5
4 2 = 5
2 3 = 2
1 3 = 5
4 3 = 5

代码

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f 
const int N=1100;
int fa[N][N],depth[N];
int h[N],e[N*2],ne[N*2],idx;  //链式前向星无向,边数得乘2
int d[N],root;
void add(int x,int y)    //链式前向星建边
{
	e[idx]=y;
	ne[idx]=h[x];
	h[x]=idx++;
}
void bfs(int u)  //广搜预处理fa数组和depth数组
{ 
	memset(depth,0x3f,sizeof(depth));
	depth[0]=0,depth[root]=1;
	queue<int>q;
	q.push(root);
	while(!q.empty()) {
		int t=q.front();
		q.pop();
		for(int i=h[t];i!=-1;i=ne[i]) {
			int j=e[i];
			if(depth[j]>depth[t]+1) {     //广搜预处理depth数组
				depth[j]=depth[t]+1;
				q.push(j);
				fa[j][0]=t;    //fa[j][0]表示父亲
				for(int k=1;k<=15;k++) {
					fa[j][k]=fa[fa[j][k-1]][k-1]; //f(i,k)=f(f(i,k-1),k-1)推导处理fa数组
				}
			}
		}
	}
}
int lca(int a,int b)
{
	if(depth[a]<depth[b]) swap(a,b);         //如果a比b浅,交换a,b
	for(int i=15;i>=0;i--) {                 //1.将a和b调到同一层
		if(depth[fa[a][i]]>=depth[b])
			a=fa[a][i];
	}
	if(a==b) return a;                       //如果调换以后相等则b为最近祖先
	for(int i=15;i>=0;i--) {                 //否则a和b一起向上跳,一直到最近祖先的儿子结点
		if(fa[a][i]!=fa[b][i]) {
			a=fa[a][i];
			b=fa[b][i];
		}
	}
	return fa[a][0];
}
int main()
{
	int n;
	cin>>n;
	memset(h,-1,sizeof(h));
	for(int i=1;i<=n;i++) {
		int x,m;
		cin>>x>>m;
		while(m--) {
			int xx;
			cin>>xx;
			d[xx]++;
			add(x,xx);
			add(xx,x);
		}
	}
	for(int i=1;i<=n;i++) if(d[i]==0) root=i;   //入度为0的点作为根结点
	// cout<<root<<endl;
	bfs(root);
	int m;
	cin>>m;
	while(m--) {
		int a,b;
		cin>>a>>b;
		int t=lca(a,b);
		cout<<a<<" "<<b<<" = "<<t<<endl;
	}
	// system("pause");
	return 0;
}

标签:结点,fa,祖先,xx,int,depth,LCA,倍增
来源: https://www.cnblogs.com/HYWdsds/p/16502084.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有