[note]最近公共祖先

最近公共祖先(LCA)https://www.luogu.org/problemnew/show/P3379

#define RG register
#include<cstdio>
#include<iostream>
using namespace std;
const int N=500010;
int n,m,s,cnt;//n点数,m边数,s根节点
int dep[N],f[N][25],last[N];//dep深度,f[i][j]表示第i个节点的2^j祖先的序号
inline int read()
{
	RG int x=0,w=1;RG char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*w;
}
struct edge{//邻接表
	int to,next;
}e[2*N];
void insert(int u,int v)//连边
{
	e[++cnt]=(edge){v,last[u]};last[u]=cnt;
	e[++cnt]=(edge){u,last[v]};last[v]=cnt;	
}
void dfs(int now)//dfs预处理出每个点的深度以及每个点的父亲
{
	for(int i=last[now];i;i=e[i].next)
	{
		int v=e[i].to;
		if(dep[v])continue;
		dep[v]=dep[now]+1;
		f[v][0]=now;//f[v][0]即父亲
		dfs(v);
	}
}
void init()
{
	dep[s]=1;//根节点深度置为1
	dfs(s);
	for(int j=1;j<=20;j++)//注意j循环在i循环外
		for(int i=1;i<=n;i++)
			f[i][j]=f[f[i][j-1]][j-1];
}
int LCA(int a,int b)
{
	if(dep[b]>dep[a])swap(a,b);
	for(int i=20;i>=0;i--)if(f[a][i]&&dep[f[a][i]]>=dep[b])a=f[a][i];//倍增上跳,使a与b位于同一深度
	if(a==b)return a;//特判b是a的祖先情况
	for(int i=20;i>=0;i--)
		if(f[a][i]&&f[b][i]&&f[a][i]!=f[b][i]){a=f[a][i];b=f[b][i];}//倍增上跳
	return f[a][0];//注意返回值,因为只跳到了LCA的儿子处
}
int main()
{
	n=read();m=read();s=read();
	for(int i=1;i<n;i++)insert(read(),read());
	init();
	while(m--)printf("%d\n",LCA(read(),read()));
	return 0;
}
posted @ 2018-02-05 16:31  sdzwyq  阅读(143)  评论(0编辑  收藏  举报