倍增 LCA
预处理复杂度\(O(n\ log\ n)\),查询复杂度\(O(log\ n)\)。
主要思想是倍增,通过预处理出夫亲的倍增数组实现快速求LCA
1 的父节点取 0 是为了方便树上差分,1 的深度设置得比 0 大是为了防止在求LCA时跳到0.
挺好理解的。
#include<bits/stdc++.h>
using namespace std;
#define file(a) freopen(#a".in","r",stdin),freopen(#a".out","w",stdout);
int n,m,s;
vector<int>head,nxt,to;
void add(int u,int v)
{
nxt.push_back(head[u]);
head[u]=to.size();
to.push_back(v);
}
int f[500010][21],dep[500010];
void dfs1(int x,int fa)
{
f[x][0]=fa;dep[x]=dep[fa]+1;
for(int i=0;i<=19;++i)
{
f[x][i+1]=f[f[x][i]][i];
}
for(int i=head[x];i!=-1;i=nxt[i])
{
if(fa==to[i]) continue;
dfs1(to[i],x);
}
}
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,&s);
head.resize(n+1,-1);
for(int i=1;i<=n-1;++i)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
dfs1(s,0);
while(m--)
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",LCA(x,y));
}
return 0;
}