luogu P1396 营救
Posted Excim
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu P1396 营救相关的知识,希望对你有一定的参考价值。
原题链接:https://www.luogu.org/problem/show?pid=1396
刚一看到这个题,马上就想起来前几天刚做的货车运输,于是迅速地敲了个最小生成树+lca求路径上最长边,写完后一看标签和难度,咦,为什么没有lca的标签啊,为什么这个题的难度只有普及/提高减啊,这个不是和货车运输差不多的吗。。。
于是愉快的交上去A掉了之后,仔细想了想新的做法,又想出两种做法:
1.倍增lca+最小生成树:
基本上同货车运输:
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; void read(int &y) { y=0;char x=getchar(); while(x<‘0‘||x>‘9‘) x=getchar(); while(x>=‘0‘&&x<=‘9‘) { y=y*10+x-‘0‘; x=getchar(); } } struct edge { int u,v,w; }e[50005]; bool cmp(edge x,edge y) { return x.w<y.w; } int fa[10005][25],maxw[10005][25]; int f[10005],head[20005],nxt[20005],to[20005],d[20005],dep[10005]; int n,m,s,t,cnt; int find(int x) { if(x==f[x]) return x; return f[x]=find(f[x]); } void add(int u,int v,int w) { to[cnt]=v; d[cnt]=w; nxt[cnt]=head[u]; head[u]=cnt++; } void dfs(int x,int y) { for(int i=head[x];i!=-1;i=nxt[i]) { if(i!=y) { dep[to[i]]=dep[x]+1; fa[to[i]][0]=x; maxw[to[i]][0]=d[i]; dfs(to[i],i^1); } } } int lca(int x,int y) { if(dep[x]>dep[y]) { int tmp=x; x=y; y=tmp; } int ans=-1; for(int i=15;i>=0;i--) { if(dep[fa[y][i]]>=dep[x]) { ans=max(ans,maxw[y][i]); y=fa[y][i]; } } if(x==y) return ans; for(int i=15;i>=0;i--) { if(fa[x][i]!=fa[y][i]) { ans=max(ans,max(maxw[x][i],maxw[y][i])); x=fa[x][i]; y=fa[y][i]; } } return ans; } int main() { read(n);read(m);read(s);read(t); for(int i=0;i<m;i++) { read(e[i].u);read(e[i].v);read(e[i].w); } sort(e,e+m,cmp); memset(head,-1,sizeof(head)); for(int i=1;i<=n;i++) f[i]=i; for(int i=0;i<m;i++) { if(find(e[i].u)!=find(e[i].v)) { add(e[i].u,e[i].v,e[i].w); add(e[i].v,e[i].u,e[i].w); f[find(e[i].u)]=find(e[i].v); } } dep[1]=1,dfs(1,-1); for(int j=1;j<=15;j++) { for(int i=1;i<=n;i++) { fa[i][j]=fa[fa[i][j-1]][j-1]; maxw[i][j]=max(maxw[i][j-1],maxw[fa[i][j-1]][j-1]); } } printf("%d",lca(s,t)); return 0; }
2.最小生成树+暴力公共祖先:
此题只有一组数据,所以我们可以使用离线算法,首先求出图的最小生成树,然后由s节点暴力向上找父亲节点,一路标记,到达根节点后停止。在由t节点向上暴力找父亲节点,到达有标记的点之后停止。
然后两点分别再向上到公共祖先,更新最大值,输出即可。
3.最小生成树+巧妙利用并查集性质:
继续使用离线算法,然后使用克鲁斯卡尔算法求最小生成树,当s与t在一个集合中时,s到t的路径就确定了,最长的边就是当前要处理的边,输出即可。
以上是关于luogu P1396 营救的主要内容,如果未能解决你的问题,请参考以下文章