最近树上公共祖先(LCA)

零 前置芝士

st表

一 正题

先预处理出来 fa 数组,其中 fai,j 代表 i2j 级祖先。

对于每一组询问 (x,y) ,找到深度大的那个点,让他先跳到和另一个一样的高度,然后一起往上跳,最后输出父亲节点。

代码

#include<bits/stdc++.h>

using namespace std;
const int N=5e5+10;
int n,m,s;

int head[N],nxt[N<<1],to[N<<1],cnt;
inline void add(int u,int v){
	to[++cnt]=v;
	nxt[cnt]=head[u];
	head[u]=cnt;
}

int dep[N],fa[N][22],lg[N];
void dfs(int u,int f){
	fa[u][0]=f;
	dep[u]=dep[f]+1;
	for(int i=1;i<=lg[dep[u]];i++) 
		fa[u][i]=fa[fa[u][i-1]][i-1];
	for(int i=head[u];i;i=nxt[i])
		if(to[i]!=f) dfs(to[i],u);
}

int lca(int x,int y){
	if(dep[x]<dep[y]) swap(x,y);
	while(dep[x]>dep[y])
		x=fa[x][lg[dep[x]-dep[y]]-1];
	if(x==y) return x;
	for(int k=lg[dep[x]]-1;k>=0;k--)
		if(fa[x][k]!=fa[y][k]) x=fa[x][k],y=fa[y][k];
	return fa[x][0];
}

int main(){
	cin>>n>>m>>s;
	for(int i=1;i<=n-1;i++){
		int x,y;
		cin>>x>>y;
		add(x,y); add(y,x);
	}
	for(int i=1;i<=n;i++)
		lg[i]=lg[i-1]+(1<<lg[i-1]==i);
	for(int i=1;i<=n;i++)
		printf("%d %d\n",i,lg[i]);
	dfs(s,0);
	for(int i=1,x,y;i<=m;i++){
		cin>>x>>y;
		printf("%d\n",lca(x,y));
	}
	return 0;
}

二 例题

略,随便找都能找到

posted @   jasony_sam  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示