题面
如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。
思路
这次我们要使用的知识点是
- 遍历这个点的每个子结点并进入子节点
- 将子节点与自己合并
- 遍历要跟它求
的点,如果这个点被访问了,这个点在并查集中的祖先便是答案
等等,你是不是蒙圈了?我们先放张图:
假设我们要求
我们在这张图上模拟一下并查集中的过程:
首先,一切还是一盘散沙:
接下来,
接着又是
注意了!!!此处敲黑板!!!此时我们访问到
后面的无用功就不放了。
于是,我们就发现了,其实我们就是把点按
代码
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现