P4281 [AHOI2008] 紧急集合 / 聚会
P4281 [AHOI2008] 紧急集合 / 聚会
题目翻译;
给你一颗数,边权为\(1\),在,给你\(x,y,z\)三个节点,求一个节点,使\(x,y,z\)到该节点的花费最小
思路:
求树上路径,我们一定会想到\(lca\),但本题要求求出\(3\)个点,那我们先求出两两之间的\(lca\),发现其中深度最深的就是答案。原因是若两点已经到了\(lca\)若它还需要继续往上跳,花费就是双倍,不如让另一点跳到该点。
实现:
因此,我们只需要求出三者任意两两间的\(lca\),在找到深度最深的,最后用深度来计算,其总花费即可;
完整代码:
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
vector<int>e[N];
int f[N][35],dep[N];
void dfs(int u,int fa){
f[u][0]=fa;
dep[u]=dep[fa]+1;
for(int i=1;i<=20;i++){
f[u][i]=f[f[u][i-1]][i-1];
}
for(auto ed:e[u]){
if(ed==fa)continue;
dfs(ed,u);
}
}
int lca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=20;i>=0;i--){
if(dep[f[x][i]]<dep[y])continue;
x=f[x][i];
}
if(x==y)return x;
for(int i=20;i>=0;i--){
if(f[x][i]==f[y][i])continue;
x=f[x][i];
y=f[y][i];
}
return f[x][0];
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,m;
cin>>n>>m;
for(int i=1;i<n;i++){
int a,b;
cin>>a>>b;
e[a].push_back(b);
e[b].push_back(a);
}
dfs(1,0);
while(m--){
int x,y,z;
cin>>x>>y>>z;
int a=lca(x,y),b=lca(x,z),c=lca(y,z);
int p,q,e,lc;
if(dep[a]>=dep[b] && dep[a]>=dep[c]){
q=x,p=y,e=z,lc=a;
}
else if(dep[b]>=dep[a] && dep[b]>=dep[c]){
q=x,p=z,e=y,lc=b;
}
else if(dep[c]>=dep[b] && dep[c]>=dep[a]){
q=z,p=y,e=x,lc=c;
}
int w=lca(q,e);
int ans=dep[q]+dep[p]-2*dep[lc]+dep[e]+dep[lc]-2*dep[w];
cout<<lc<<" "<<ans<<endl;
}
}
最近公共祖先讲解
本文作者:XichenOC
本文链接:https://www.cnblogs.com/XichenOC/p/18682378
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步