题面

如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。

思路

这次我们要使用的知识点是 dfs 和并查集,这个 tarjan 是离线的,我们要先把每个点的每一个要跟它求 LCA 的点给记录下来,接下来用 dfs 跑这么个流程:

  1. 遍历这个点的每个子结点并进入子节点
  2. 将子节点与自己合并
  3. 遍历要跟它求 LCA 的点,如果这个点被访问了,这个点在并查集中的祖先便是答案

等等,你是不是蒙圈了?我们先放张图:

假设我们要求 LCA(3,6)

我们在这张图上模拟一下并查集中的过程:

首先,一切还是一盘散沙:

接下来,3 和它的父节点 4 合并起来了,由于与 3 它相关联的 6 还没访问,此时无法更新任何答案:

接着又是 5,4 以及 2,5,都无法更新答案:

注意了!!!此处敲黑板!!!此时我们访问到 2 的另一个子节点 6,此时我们便发现,3 已被访问,于是答案是 2 !!!

后面的无用功就不放了。

于是,我们就发现了,其实我们就是把点按 dfn 序不断合并,当两个点要合并在一起时,此时的祖先便是答案,就像这样:

xy 便是要求 LCA 的两个点,它们现在刚好就合并到一起,显然只有到它们的公共祖先它们才会合并在一起,再由于回溯时是从深到低,所以第一次合并在一起时一定是到 LCA 了。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdio>
#include<string>
#include<iomanip>
using namespace std;
const int N=5e5+10;
int n,m,s;
struct edge{
	int to,nxt;
}g[N<<1];
int head[N],tot1=0;
struct qry{
	int to,nxt,idx;
}q[N<<1];
int qhead[N],tot2=0;
int ans[N];
void add(int x,int y){
	tot1++;
	g[tot1].to=y;
	g[tot1].nxt=head[x];
	head[x]=tot1;
	return;
}
void qadd(int x,int y,int z){
	tot2++;
	q[tot2].to=y;
	q[tot2].nxt=qhead[x];
	q[tot2].idx=z;
	qhead[x]=tot2;
	return;
}
int fa[N],vis[N];
int Find(int x){
	return (fa[x]==x)?x:(fa[x]=Find(fa[x]));
}
void dfs(int u,int f){
	vis[u]=1;
	for(int i=head[u];i;i=g[i].nxt){
		int v=g[i].to;
		if(v!=f){
			dfs(v,u);
			fa[v]=u;
		}
	}
	for(int i=qhead[u];i;i=q[i].nxt){
		int v=q[i].to;
		if(vis[v]){
			ans[q[i].idx]=Find(v);
		}
	}
	return;
}
int main(){
    cin.tie(0);
	ios::sync_with_stdio(false);
	cin>>n>>m>>s;
	for(int i=1;i<n;i++){
		int u,v;
		cin>>u>>v;
		add(u,v);
		add(v,u);
	}
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		qadd(u,v,i);
		qadd(v,u,i);
	}
	for(int i=1;i<=n;i++)fa[i]=i;
	dfs(s,0);
	for(int i=1;i<=m;i++){
		cout<<ans[i]<<"\n";
	}
	cout<<flush;
    return 0;
}
posted on   PengDave  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示