//LCA找最近公共祖先,被增法模板
//f[y][j]的意思是从y节点走2的j次方走到的节点
#include<bits/stdc++.h>
using namespace std;
const int N=110;
int d[N],dep[10],f[N][10];//d[N]记录每个节点的深度,dep记录每层节点个数
int n,u,v,t,tot=0,ans,lca;
int head[N],Next[2*N],ver[2*N];
void add(int x,int y)
{
ver[++tot]=y;
Next[tot]=head[x];
head[x]=tot;
}//领接表存边
void bfs()
{
queue<int> q;
d[1]=1;
dep[1]++;
q.push(1);
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=head[x];i;i=Next[i])
{
int y=ver[i];
if(d[y]) continue;
d[y]=d[x]+1;
dep[d[y]]++;//存储每行有几个结点
f[y][0]=x;//y的父节点是x
for(int j=1;j<=t;j++)//遍历每层
{
f[y][j]=f[f[y][j-1]][j-1];
}
q.push(y);
}
}
}//预处理
int LCA(int x,int y)//s树上倍增法
{
if(d[x]>d[y]) swap(x,y);//保证x深度小于y
for(int i=t;i>=0;i--)//y向上跳,跳到x同层
{
if(d[f[y][i]]>=d[x])//y点还在x下面,可以跳
{
y=f[y][i];//更新跳后y的位置
}
}
if(x==y) return x;//能跳到同一个点,找到最小公共祖先
for(int i=t;i>=0;i--)//x,y同层,一起向上跳 保证一直不相等
{//跳到同一个节点时可能出了最小公共祖先
if(f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];//更新
}
}
return f[x][0];//当前节点的父节点就是 lca
}
int main()
{
cin>>n;
t=log2(n)+1;
for(int i=1;i<n;i++)
{
int x,y;
cin>>x>>y;
add(x,y);
add(y,x);
}
cin>>u>>v;
bfs();
lca=LCA(u,v);
for(int i=1;i<=n;i++)
{
ans=max(ans,d[i]);//最深的深度
}
cout<<ans<<endl;
ans=0;
for(int i=1;i<=t;i++)//遍历每层节点个数
{
ans=max(ans,dep[i]);
}
cout<<ans<<endl;
int len=(d[u]-d[lca])*2+(d[v]-d[lca]);//此题规定的两点距离公式
cout<<len<<endl;
return 0;
}
LCA详解 - TEoS - 博客园 (cnblogs.com)
例题P3884 [JLOI2009] 二叉树问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
P3379 【模板】最近公共祖先(LCA) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<iostream>
#include<cstdio>
#include<queue>
#include<cmath>
using namespace std;
const int N=6e5;
int n,m,s,t,tot=0,f[N][20],d[N],ver[2*N],Next[2*N],head[N];
queue<int> q;
void add(int x,int y)
{
ver[++tot]=y,Next[tot]=head[x],head[x]=tot;
}//邻接表存边操作。由于只求LCA时不关心边权,因此可以不存边权
void bfs()
{
q.push(s);
d[s]=1;//将根节点入队并标记
while(q.size())
{
int x=q.front();q.pop();//取出队头
for(int i=head[x];i;i=Next[i])
{
int y=ver[i];
if(d[y])
continue;
d[y]=d[x]+1;
f[y][0]=x;//初始化,因为y的父亲节点就是x
for(int j=1;j<=t;j++)
f[y][j]=f[f[y][j-1]][j-1];//递推f数组
q.push(y);
}
}
}
int lca(int x,int y)
{
if(d[x]>d[y])
swap(x,y);
for(int i=t;i>=0;i--)
if(d[f[y][i]]>=d[x])
y=f[y][i];//尝试上移y
if(x==y)
return x;//若相同说明找到了LCA
for(int i=t;i>=0;i--)
if(f[x][i]!=f[y][i])
{
x=f[x][i],y=f[y][i];
}//尝试上移x、y并保持它们不相遇
return f[x][0];//当前节点的父节点即为LCA
}
int main()
{
cin>>n>>m>>s;
t=log2(n)+1;
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
bfs();
while(m--)
{
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",lca(a,b));
}
return 0;
}