倍增最近公共祖先(LCA)

倍增最近公共祖先(LCA)

标签(空格分隔): 模板

#include <bits/stdc++.h>
using namespace std;


const int MAXN = 5e5 + 50;
int n, m, s;
int fa[MAXN][50], lg[MAXN], dep[MAXN];

vector<int> e[MAXN];


inline int read()
{
	int res = 0;
	char ch = getchar();
	
	while(48 > ch || ch > 57){
		ch = getchar();
	}
	
	while(48 <= ch && ch <= 57){
		res = (res << 3) + (res << 1) + (ch - 48);
		ch = getchar();
	}
	
	return res;
}

void add_edge(int u, int v)
{
	e[u].push_back(v);
	e[v].push_back(u);
	
	return; 
}

void build_lca(int now)
{
//	cout << "*";
	for(int i = 1; i <= 30 && fa[now][i - 1]; i ++ )
		fa[now][i] = fa[fa[now][i - 1]][i - 1];
	
	for(int v : e[now]){
		if(v == fa[now][0])   continue;
		
		dep[v] = dep[now] + 1;
		fa[v][0] = now;
		build_lca(v);
	} 
	
	return;
}

int get_lca(int u, int v)
{
	if(dep[u] < dep[v])  swap(u, v);
	
	while(dep[u] > dep[v])
		u = fa[u][lg[dep[u] - dep[v]] - 1];
	if(u == v)	return u;
	
	for(int i = lg[dep[u]]; i >= 0; i --){
		if(fa[u][i] != fa[v][i])
			u = fa[u][i], v = fa[v][i];
	}
	
	return fa[u][0];
}
int main()
{
	
	n = read(), m = read(), s = read();
	
	for(int i = 0; i < n - 1; i ++){
		int u = read(), v = read();
		add_edge(u, v);
	} 
	
	
	build_lca(s); 
	
	for(int i = 1; i <= n; i ++)
		lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
	for(int i = 0; i < m; i ++){
		int u = read(), v = read();
		printf("%d\n", get_lca(u, v));
	}
	return 0;
}
posted @ 2020-12-10 19:44  SatCH  阅读(44)  评论(0编辑  收藏  举报