Problem: [模板]最近公共祖先LCA
Time Limit: 3 Sec Memory Limit: 128 MB
Description
给出N,Q
代表一个树有N个点 ,树的根为1
Q代表有Q个询问,询问A,B的最近公共祖先是哪一个.
Input
- 第一行给出N,Q
- 下面N-1行描述这个树,格式为A,B,代表A为B的Son
- 接来下Q行 给出A,B,代表进行询问A,B的LCA是哪一个.
Output
- 针对每个询问输出结果
Sample Input
4 2
2 1
3 2
4 2
3 4
4 2
Sample Output
2
2
代码如下
#include<cstdio>
#include<algorithm>
#define N 1000002
using namespace std;
int n,q,rt,f[N][20],dep[N],a[N],pre[N],now[N],son[N],tot;
bool bl[N];
inline void addx(int x,int y) { //x到y连一条边
pre[++tot]=now[x];
now[x]=tot;
son[tot]=y;
}
void dfs(int u,int d) {
dep[u]=d; //u的深度为d
bl[u]=1; //标记u这个点被走过了
for(int ls=now[u]; ls; ls=pre[ls]) { //枚举所有与u相连的边
int c=son[ls]; //拿出u的每一个子结点
if(!bl[c]) { //如果这个点没有走过的话
f[c][0]=u; //c这个点的父亲为u
dfs(c,d+1);
}
}
}
int lca(int x,int y) {
if(dep[x]<dep[y]) //如果x的深度小于y,就交换一下
swap(x,y);
for(int i=19; i>=0; i--)
if(dep[f[x][i]]>=dep[y])
x=f[x][i];
if(x==y) //如果跳到了同一个点.直接返回答案
return x;
for(int i=19; i>=0; i--) //逆循环枚举
if(f[x][i]!=f[y][i]) //如果jump到了两个不同的点
x=f[x][i],y=f[y][i];
return f[x][0]; //这个点的父亲点就是答案
}
int main() {
int x,y;
scanf("%d %d",&n,&q);
rt=1;
for(int i=1,x,y; i<n; i++) {
scanf("%d%d",&x,&y);
addx(x,y),addx(y,x);
}
dfs(rt,1);
for(int j=1; j<20; j++) //处理出所有点向上跳2^j步跳到哪个点
for(int i=1; i<=n; i++)
f[i][j]=f[f[i][j-1]][j-1];
for(int i=1; i<=q; i++) {
scanf("%d%d",&x,&y);
printf("%d
",lca(x,y));
}
}