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

Luogu P3379 【模板】最近公共祖先(LCA)_第1张图片
这道题是LCA模板题!

LCA:

基于有根树最近公共祖先问题
在有根树T中,
询问一个距离根最远的结点x,
使得x同时为结点u、v的祖先,
这个祖先节点即为lca。
同时lca一定是u、v路径上的点

开标解释:

#include
#include
#include
#include
#include
using namespace std;

int ls[1000010],dep[1000010],f[1000010][20];  //f[x][y]表示在x点向上跳y^k步。
int n,m,s,tot,x,y;

struct node
{
     
	int y,next;
}a[5000010];
void finddep(int x,int fa)
{
     
	f[x][0]=fa;//初始化父亲(向上一个就是父亲0^k=1)
	dep[x]=dep[fa]+1;
	for(int i=ls[x]; i; i=a[i].next)  //找深度dep
	 {
     
	 	int y=a[i].y;
	 	if(y==fa) continue;
	 	finddep(y,x);
	 }
}
void add(int x,int y)
{
     
	a[++tot].y=y;
	a[tot].next=ls[x];
	ls[x]=tot;
}
int lca(int x,int y)
{
     
	if(dep[x]>dep[y])   //将深度生的放成y,另一个放成x
	  swap(x,y);
	int d=dep[y]-dep[x],k=19,t=1<<k;  //d为深度,k是要放2^k,t为了比较。
	while(d)   //将x,y移到同一深度
	 {
     
	 	if(d>=t)  //当当前d可以容纳y跳t步
		  d-=t,y=f[y][k];  //深度往上跳t步,y放成往上跳T步的状态
	 	k--,t=1<<k;  //跳的范围不断缩短
	 }
	if(x==y)   //如果刚好跳到同一节点,直接返回。
	  return x;
	k=19;
	while(k>=0)  //从同一深度往上跳
	 {
     
	 	if(f[x][k]!=f[y][k])   //不是一个父亲就跳,找到了就一直停留
	 	 {
     
	 	 	x=f[x][k];   //移动x往上跳2^k步;
	 	 	y=f[y][k];   //移动y往上跳2^k步;
	 	 }
	 	k--;  //跳的范围不断缩短
	 }
	return f[x][0];  //最后跳一步到父亲节点(因为找到了就停留)
}
int main()
{
     
	cin>>n>>m>>s;
    for(int i=1; i<=n-1; i++)
     {
     
     	scanf("%d%d",&x,&y);
     	add(x,y);
     	add(y,x);
     }
    finddep(s,0);
    for(int j=1; j<=19; j++)  //j最大2^20 
     for(int i=1; i<=n; i++)  //枚举起点 
      f[i][j]=f[f[i][j-1]][j-1];
    while(m--)
     {
     
     	scanf("%d%d",&x,&y);
     	cout<<lca(x,y)<<endl;
     }
	return 0;
}

你可能感兴趣的:(题解(较高质量),lca)