D. Maximum Distance
題目鏈接:https://codeforces.com/contest/1081/problem/D
題意:
給出一個連通圖以及一些特殊點,現在定義cost(u,v)為一條從u到v的路徑上面邊權的最大值,然后定義dis(u,v)為從u到v所有路徑上面cost的最小值。
最后求所有特殊點到其它特殊點的最大距離...
題解:
這個題意似乎有點繞...
我們考慮一下最小生成樹,那么點與點之間的距離就為最小生成樹路徑上面邊權的最大值。
我們來證明一下:假設在最小生成樹上面的路徑cost為w1,另外在原圖中還有一條路徑從u到v,其cost為w2,那么必然有w2>w1的。那么我們最后的dis一定是w1。
那么我們現在的目標就是求特殊點到特殊點之間的最大距離。注意一下這里是從一個特殊點到其它所有特殊點的最大距離。
我們知道在Kruskal加邊時,后加的邊權一定時大於前面的邊權的,既然要求最大權值,那么我們可以想加的最后一條邊是否可以作為答案。
我們假設現在有兩個集合,現在將其連接起來,當滿足兩個集合里面都有特殊點時我們就可以更新答案了,否則就不行。
所以我們合並的時候順帶維護一下集合里面特殊點的信息就可以了。
代碼如下:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N =1e5+5; struct Edge{ int u,v,w; bool operator < (const Edge&A)const{ return w<A.w; } }e[N]; int n,m,k; int a[N],f[N],val[N]; int find(int x){ if(x==f[x]) return f[x]; f[x]=find(f[x]); return f[x]; } int main(){ cin>>n>>m>>k; int tot=k; for(int i=1,t;i<=k;i++){ cin>>t; a[t]=1; } for(int i=1;i<=m;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); e[i]=Edge{u,v,w}; } for(int i=1;i<=n;i++) f[i]=i; sort(e+1,e+m+1); int ans; for(int i=1;i<=m;i++){ int u=e[i].u,v=e[i].v,w=e[i].w; int fx=find(u),fy=find(v); if(fx==fy) continue; f[fx]=fy; if(a[u]) val[fx]++;if(a[v]) val[fy]++; if(val[fx]&&val[fy]) ans=w; val[fy]+=val[fx]; } for(int i=1;i<=k;i++) cout<<ans<<" "; return 0; }