【模板】最近公共祖先(LCA)

Description

给你一棵有根树,1为根节点,要求你计算出指定两个结点的最近公共祖先。

Input

输入文件的第一行两个整数n和m,n为结点个数(2<=n,m<=100,000),结点编号为1到n,m表示询问次数。
接下来n-1行,每行两个整数x,y,表示x和y之间有一条边相连;
接下来m行,每行两个整数a和b,要求计算出结点a和b的最近公共祖先。

Output

输出文件共m行,每行为一个询问的最近公共祖先的编号。

Sample Input

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

Sample Output

2
2


思路

  • 树上倍增求LCA模板

代码

#include <iostream>
#include <cstdio>
#include <cmath>
#define maxn 100005
using namespace std;
int n,m,cnt,head[maxn],fa[maxn][17],deep[maxn];
struct node{int next,to;}e[maxn<<1];
void addedge(int x,int y){e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt;}
void dfs(int u,int pre)
{
	fa[u][0]=pre; deep[u]=deep[pre]+1;
	for(int i=head[u];i;i=e[i].next)
	{
		int v=e[i].to;
		if(v!=pre) dfs(v,u);
	}
}
void st()
{
	for(int i=1;i<=log2(n);++i)
		for(int j=1;j<=n;++j)
			fa[j][i]=fa[fa[j][i-1]][i-1];
}
int lca(int u,int v)
{
	if(deep[u]<deep[v]) swap(u,v);
	while(deep[u]>deep[v]) u=fa[u][(int)log2(deep[u]-deep[v])];
	if(u==v) return u;
	for(int i=log2(n);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%d",&n,&m);
	for(int i=1,u,v;i<n;++i) scanf("%d%d",&u,&v),addedge(u,v),addedge(v,u);
	dfs(1,0); st();
	while(m--)
	{
		int u,v; scanf("%d%d",&u,&v);
		printf("%d
",lca(u,v));
	}
	return 0;
}
原文地址:https://www.cnblogs.com/wuwendongxi/p/13516326.html