模板: 最近公共祖先(倍增实现) LCA-Doubling
Lowest Common Ancestors (LCA)-Doubling
最近公共祖先(倍增实现)
Brief Introduction
在图论和CS中,两个节点\(v\)和\(w\)在树上或者有向无环图中的最近公共祖先(LCA)\(T\)是指,同时拥有\(v\)和\(w\)这两个节点作为后代的最深的节点。我们定义每个节点也是其本省的后代(所以如果\(v\)是\(w\)的后代,\(w\)就是它们的最近公共祖先)
In graph theory and computer science, the lowest common ancestor (LCA) of two nodes v and w in a tree or directed acyclic graph (DAG) T is the lowest (i.e. deepest) node that has both v and w as descendants, where we define each node to be a descendant of itself (so if v has a direct connection from w, w is the lowest common ancestor).
Algorithm
本文介绍求LCA在线算法中的倍增实现,初始化复杂度\(O(n)\),单次查询复杂度\(O(\log n)\)
算法的核心在于ST表,用 \(\text S\text T[cur][i]\) 数组存放 \(cur\) 节点的第\(2^i\)辈祖先。
用DFS从根遍历初始化,打表转移方程\(\text S\text T[cur][i]=\text S\text T[\text S\text T[cur][i-1]][i-1]\)。 复杂度\(O(\log n)\)。
询问时,先将\(u\)和\(w\)某一个更深的点,利用ST表,向祖先移动至同样深度。
如果此时\(u=w\)则该节点便是 LCA,
否则同样深度下\(u \not=w\),则用ST表从最深的深度递减试探,将\(u,w\)在ST表移动至最浅的祖先在同样深度下,\(u\not=w\)的节点,它们的父节点便是所求LCA。
Template Code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 500005
#define MAXM 500005
#define MAXLN 25
using namespace std;
struct edge{
int to,next;
}e[MAXM<<1];
int tot,head[MAXN];
void add(int x,int y){
tot++;
e[tot].to=y;
e[tot].next=head[x];
head[x]=tot;
}
int dep[MAXN],lgd[MAXN],st[MAXN][MAXLN];
void dfs(int cur,int fa){
dep[cur]=dep[fa]+1;
st[cur][0]=fa;
for(lgd[cur]=1;(1<<lgd[cur])<=dep[cur];lgd[cur]++)
st[cur][lgd[cur]]=st[st[cur][lgd[cur]-1]][lgd[cur]-1];
for(int p=head[cur];p;p=e[p].next){
if(e[p].to==fa) continue;
dfs(e[p].to,cur);
}
}
int lca(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int i=0;dep[x]-dep[y];i++)
if((dep[x]-dep[y])&(1<<i)) x=st[x][i];
if(x==y) return x;
for(int i=lgd[x];i>=0;i--)
if(st[x][i]!=st[y][i])
x=st[x][i], y=st[y][i];
return st[x][0];
}
int n,m,s;
int main(){
scanf("%d %d %d", &n, &m, &s);
tot=0;
memset(head+1,0,n*sizeof(head[0]));
for(int i=1;i<n;i++){
int f,g;
scanf("%d %d", &f, &g);
add(f,g);
add(g,f);
}
dep[0]=0;
dfs(s,0);
for(int i=1;i<=m;i++){
int f,g;
scanf("%d %d", &f, &g);
printf("%d\n", lca(f,g));
}
return 0;
}