[luogu p3379]【模板】最近公共祖先(LCA){树上倍增法}

题目

https://www.luogu.org/problemnew/show/P3379


解题思路(树上倍增)

f [ x ] [ k f[x][k f[x][k表示 x x x 2 k 2^{k} 2k辈祖先,即从 x x x向根节点走 2 k 2^{k} 2k步到达的结点。特别的,若该结点不存在,则令 f [ x ] [ k ] = 0 f[x][k]=0 f[x][k]=0 f [ x ] [ 0 ] f[x][0] f[x][0]就是 x x x的父结点。
d e p [ i ] dep[i] dep[i]表示该结点的深度。
L c a Lca Lca的时候,用二进制的拆分思想,把 x x x向上调整到与 y y y同一深度。


代码

#include
#include
using namespace std; 
struct node{
	int y,next; 
}a[1000010];
int len,last[500010],n,m,k,x,y,dep[500010],f[500010][21]; 
void add(int x,int y)
{ a[++len]={y,last[x]}; last[x]=len;}
void Deal_first(int u,int father)
{
	dep[u]=dep[father]+1; 
	for (int i=0;i<=19;i++) f[u][i+1]=f[f[u][i]][i]; 
    for (int i=last[u];i;i=a[i].next)
    {
    	if (a[i].y==father) continue; 
    	f[a[i].y][0]=u; Deal_first(a[i].y,u); 
	}
}
int lca(int x,int y)
{
	if (dep[x]<dep[y]) swap(x,y); 
	for (int i=20;i>=0;i--)
	 {
	 	if (dep[f[x][i]]>=dep[y]) x=f[x][i]; 
	 	if (x==y) return x; 
	 }
	for (int i=20;i>=0;i--)
	 if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
	return f[x][0]; 
}
int main()
{
	scanf("%d%d%d",&n,&m,&k); 
	for (int i=1;i<=n-1;i++)
	 scanf("%d%d",&x,&y),add(x,y),add(y,x); 
	Deal_first(k,0); 
	for (int i=1;i<=m;i++)
	 scanf("%d%d",&x,&y),printf("%d\n",lca(x,y)); 
}

你可能感兴趣的:(LCA问题(/tarjan))