1. 程式人生 > 實用技巧 >最小公共祖先模板

最小公共祖先模板

#include <bits/stdc++.h>
using namespace std;
int fa[2000005][35];//結點i的第2^j級祖先 
int dpt[2000010];
int head[2000010];
int ver[2000010];
int nxt[2000010];
int lg[2000010];//預處理一下log(i)+1 
int tot=0;
int n,m,s;

void refer()
{
	for(int i=1;i<=n;i++)
	{
		lg[i]=lg[i-1]+(1<<lg[i-1]==i); 
	}
}
void dfs(int x,int f)
{
	fa[x][0]=f; //結點的第1級祖先就是他的父節點
	dpt[x]=dpt[f]+1; /*記錄結點深度*/ 
	int t=lg[dpt[x]];
	for(int i=1;i<=t;i++)
	{
		fa[x][i]=fa[fa[x][i-1]][i-1];//x的2^i級祖先=x的2^(i-1)級祖先的2^(i-1)級祖先 
	}
	for(int i=head[x];i;i=nxt[i])
	{
		int y=ver[i];
		if(y==f) continue;
		dfs(y,x);//繼續向下 
	}
}
int latest_common_ancestors(int x,int y)
{
	if(dpt[x]<dpt[y]) swap(x,y);//將x點設為深度較深的點 
	while(dpt[x]>dpt[y])
	{
		x=fa[x][lg[dpt[x]-dpt[y]]-1];
	}
	if(x==y) return y;//x跳上來發現就是y,那y就肯定是LCA
	for(int k=lg[dpt[x]]-1;k>=0;k--) //向上
	{
		if(fa[x][k]!=fa[y][k])//因為我們只跳到公共祖先的下一層所以x,y肯定不相等 ,判定他們的父節點是否相等不相等就繼續往下; 
		{
			x=fa[x][k],y=fa[y][k];
		}
	}
	return fa[x][0];//返回的是父節點 
}
void add(int x,int y)
{
	ver[++tot]=y;
	nxt[tot]=head[x];
	head[x]=tot;
}
int main()
{
////	freopen("answer.txt","w",stdout);
	scanf("%d%d%d",&n,&m,&s);
	refer();//預處理log2(i)+1; 
	for(int i=1;i<n;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	dfs(s,s);
	for(int i=1;i<=m;i++)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		printf("%d\n",latest_common_ancestors(a,b));
	}
	return 0;
}