P3379 【模板】最近公共祖先(LCA)

题目传送门

思路:模板题思路不多说,唯一需要注意的一点是此题用vector会多耗费时间(因为内存不够会自动申请2倍内存,然后复制元素到新内存耗费时间),用链式快很多。具体见代码。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
const int M=log2(N);
int fa[N][M],dep[N],mx,cnt=1,h[N];
struct edge{
	int to,nt;
}e[N];
void add(int u,int v){
	e[cnt].to=v;
	e[cnt].nt=h[u];
	h[u]=cnt++;
}
void dfs(int u){
	for(int i=1;i<=mx;i++)
		if(fa[u][i-1]) //如果u不存在第2^(i-1)父亲,则肯定不存在fa[u][i] 
			fa[u][i]=fa[fa[u][i-1]][i-1];
		else break;
	for(int i=h[u];i;i=e[i].nt){
		int v=e[i].to;
		if(v!=fa[u][0]){
			fa[v][0]=u;
			dep[v]=dep[u]+1;
			dfs(v);
		}
	}
}
int lca(int u,int v){
	if(dep[u]<dep[v]) swap(u,v);//默认u为较大深度的结点 
	int delta=dep[u]-dep[v];//深度差值. 
	for(int i=0;i<=mx;i++) //将u提到与v同深度 
		if((1<<i)&delta)
			u=fa[u][i];
	if(u==v) return u;//入股此时相等说明u,v的祖先就是u(v) 
	for(int i=mx;i>=0;i--)//这里要从大往小提,来达到越提越精确的效果。 
		if(fa[u][i]!=fa[v][i]) //如果父亲不相等就继续一起往上题 
		{
			u=fa[u][i];
			v=fa[v][i];
		}
	return fa[u][0];//这是u,v的父亲就是他们的LCA 
}
int main(){
	int n,m,s,a,b;
	scanf("%d%d%d",&n,&m,&s);
	mx=log2(n);//最大移动 
	for(int i=1;i<n;i++){
			scanf("%d%d",&a,&b);
			add(a,b);
			add(b,a);
	}
	dfs(s);//从根结点搜 
	while(m--){
		scanf("%d%d",&a,&b);
		printf("%d\n",lca(a,b));
	}
	return 0;
}