LCA模板

倍增

时间复杂度 \(O(n\log n)\)

代码

#include<bits/stdc++.h>
using namespace std;
int anc[500010][21];//anc[i][j]表示i节点的2^j级祖先
int n,m,s;
int d[500010];//d数组表示当前节点的深度
vector<int> p[500010];
void dfs(int u,int fa){
	for(int i=0;i<p[u].size();i++){
		int v=p[u][i];
		if(v==fa) continue;
		d[v]=d[u]+1;//子节点的深度是父节点+1
		anc[v][0]=u;//子节点的2^0级节点是父节点
		dfs(v,u);
	}
}
void init(){
	for(int j=1;j<=18;j++)//根据题目更改
		for(int i=1;i<=n;i++)
			anc[i][j]=anc[anc[i][j-1]][j-1];
}
int LCA(int u,int v){
	if(d[u]<d[v]) swap(u,v);//将u当做深度较深的节点
	for(int i=18;i>=0;i--)
		if(d[anc[u][i]]>=d[v])
			u=anc[u][i];//枚举二进制将u往上提
	if(u==v) return u;
	for(int i=18;i>=0;i--)
		if(anc[u][i]!=anc[v][i])
			u=anc[u][i],v=anc[v][i];//用同样的方法提两个节点,直到相同
	return anc[u][0];
}
int main(){
	cin>>n>>m>>s;
	for(int i=1;i<=n-1;i++){
		int u,v;
		cin>>u>>v;
		p[u].push_back(v);
		p[v].push_back(u);
	}
	d[s]=1,dfs(s,0);
	init();
	while(m--){
		int u,v;
		cin>>u>>v;
		cout<<LCA(u,v)<<'\n';
	}
	return 0;
}

Tarjan

时间复杂度 \(O(n+m)\)

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
struct node{int u,id;};
int n,m,s;
vector<int> p[500010];
vector<node> Q[500010];
int fa[500010];
bool vis[500010];
int ans[500010];
int find(int x){
	if(fa[x]==x) return x;
	return fa[x]=find(fa[x]);
}//并查集
void Tarjan(int u){
	fa[u]=u;
	vis[u]=1;
	for(int i=0;i<p[u].size();i++){
		int v=p[u][i];
		if(vis[v]) continue;
		Tarjan(v);
		fa[v]=u;
	}
	for(int i=0;i<Q[u].size();i++){
		node v=Q[u][i];
		if(!vis[v.u]) continue;
		ans[v.id]=find(v.u);
	}
}
signed main(){
	cin>>n>>m>>s;
	for(int i=1;i<=n-1;i++){
		int u,v;
		cin>>u>>v;
		p[u].push_back(v);
		p[v].push_back(u);
	}
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		Q[u].push_back({v,i});
		Q[v].push_back({u,i});
	}
	Tarjan(s);
	for(int i=1;i<=m;i++) cout<<ans[i]<<'\n';
	return 0;
}
posted @ 2025-05-23 20:02  Loyal_Soldier  阅读(15)  评论(0)    收藏  举报