【模板】最近公共祖先(LCA)
Description
给你一棵有根树,1为根节点,要求你计算出指定两个结点的最近公共祖先。
Input
输入文件的第一行两个整数n和m,n为结点个数(2<=n,m<=100,000),结点编号为1到n,m表示询问次数。
接下来n-1行,每行两个整数x,y,表示x和y之间有一条边相连;
接下来m行,每行两个整数a和b,要求计算出结点a和b的最近公共祖先。
Output
输出文件共m行,每行为一个询问的最近公共祖先的编号。
Sample Input
5 2
1 2
2 3
2 4
5 4
2 5
3 5
Sample Output
2
2
思路
- 树上倍增求LCA模板
代码
#include <iostream>
#include <cstdio>
#include <cmath>
#define maxn 100005
using namespace std;
int n,m,cnt,head[maxn],fa[maxn][17],deep[maxn];
struct node{int next,to;}e[maxn<<1];
void addedge(int x,int y){e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt;}
void dfs(int u,int pre)
{
fa[u][0]=pre; deep[u]=deep[pre]+1;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(v!=pre) dfs(v,u);
}
}
void st()
{
for(int i=1;i<=log2(n);++i)
for(int j=1;j<=n;++j)
fa[j][i]=fa[fa[j][i-1]][i-1];
}
int lca(int u,int v)
{
if(deep[u]<deep[v]) swap(u,v);
while(deep[u]>deep[v]) u=fa[u][(int)log2(deep[u]-deep[v])];
if(u==v) return u;
for(int i=log2(n);i>=0;--i)
if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
return fa[u][0];
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1,u,v;i<n;++i) scanf("%d%d",&u,&v),addedge(u,v),addedge(v,u);
dfs(1,0); st();
while(m--)
{
int u,v; scanf("%d%d",&u,&v);
printf("%d
",lca(u,v));
}
return 0;
}