Problem: [模板]最近公共祖先LCA

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\n",lca(x,y));
	}

}
posted @ 2019-01-27 11:44  ZhaoChongyan  阅读(111)  评论(0编辑  收藏  举报