最近公共祖先
1.暴力
将点按照父子关系依次向上查询,知道两个点发生重合
# include <stdio.h>
# include <string.h>
# define N 40010
# define M 2*N
using namespace std;
int Next[M],head[N],ver[M],edge[M];
int depth[N],father[M],D[M];
int tot=-1,n,m;
void ADD(int x,int y,int z)
{
ver[++tot]=y;
edge[tot]=z;
Next[tot]=head[x];
head[x]=tot;
}
int LCA(int x,int y)
{
while(x!=y)
{
if(depth[x]>=depth[y])x=father[x];
else y=father[y];
}
return x;
}
void dfs(int x,int fa)
{
int y,z;
father[x]=fa;
depth[x]=depth[fa]+1;
for(int i=head[x]; ~i; i=Next[i])
{
y=ver[i];
z=edge[i];
if(y==fa)continue;
D[y]=D[x]+z;
dfs(y,x);//查找儿子节点
}//此dfs是为了求得depth[]数组
}
int main()
{
int T,x,y,z;
register int i;
scanf("%d%d",&n,&m);
memset(head,0xff,sizeof(head));
tot=-1;
for(int i=1; i<n; i++)
{
scanf("%d%d%d",&x,&y,&z);
ADD(x,y,z);
ADD(y,x,z);//双向边
}
dfs(1,-1);
while(m--)
{
scanf("%d%d",&x,&y);
printf("%d
",D[x]+D[y]-2*D[LCA(x,y)]);
}
return 0;
}
2.树上倍增
在进行 dfs 的时候处理出每个节点的父子关系,在查询时以 (2^i) 为单位向上倍增,先将两个节点的深度调整一致,然后将两个点同时向上查询,最后两点重合时,该点即为两个点的LCA,同时也可结合倍增的处理一些权值的问题
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<math.h>
#include<vector>
#include<queue>
#define ll long long
const ll maxn=1e5+10;
ll n,q,tot,ans1,ans2;
ll head[maxn*2],dep[maxn];
ll fa[maxn][22],minn[maxn][22],maxx[maxn][22];
struct node
{
ll u,v,w,nxt;
} s[maxn*2];
inline void add(ll u,ll v,ll w)
{
s[++tot].v=v;
s[tot].w=w;
s[tot].nxt=head[u];
head[u]=tot;
}
inline void dfs(ll x,ll f)
{
fa[x][0]=f;
dep[x]=dep[f]+1;
for(int i=head[x];i;i=s[i].nxt)
{
ll y=s[i].v;
if(y==f) continue;
minn[y][0]=s[i].w;
maxx[y][0]=s[i].w;
dfs(y,x);
}
}
inline void lca(ll x,ll y)
{
if(dep[x]<dep[y]) std::swap(x,y);
for(int i=18;i>=0;i--)
{
if(dep[fa[x][i]]>=dep[y])
{
ans1=std::max(ans1,maxx[x][i]);
ans2=std::min(ans2,minn[x][i]);
x=fa[x][i];
}
}
if(x==y) return ;
for(int i=18;i>=0;i--)
{
if(fa[x][i]!=fa[y][i])
{
ans1=std::max(ans1,std::max(maxx[x][i],maxx[y][i]));
ans2=std::min(ans2,std::min(minn[x][i],minn[y][i]));
x=fa[x][i];
y=fa[y][i];
}
}
ans1=std::max(ans1,std::max(maxx[x][0],maxx[y][0]));
ans2=std::min(ans2,std::min(minn[x][0],minn[y][0]));
}
int main(void)
{
scanf("%lld",&n);
memset(minn,0x3f,sizeof(minn));
for(int i=1;i<=n-1;i++)
{
ll x,y,z;
scanf("%lld %lld %lld",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
dfs(1,0);
for(int j=1;j<=18;j++)
{
for(int i=1;i<=n;i++)
{
fa[i][j]=fa[fa[i][j-1]][j-1];
minn[i][j]=std::min(minn[i][j-1],minn[fa[i][j-1]][j-1]);
maxx[i][j]=std::max(maxx[i][j-1],maxx[fa[i][j-1]][j-1]);
}
}
scanf("%lld",&q);
for(int i=1;i<=q;i++)
{
ll x,y;
ans1=-maxn*maxn*maxn;
ans2=maxn*maxn*maxn;
scanf("%lld %lld",&x,&y);
lca(x,y);
printf("%lld %lld
",ans2,ans1);
}
return 0;
}