1. 程式人生 > >Avito Cool Challenge 2018:D. Maximum Distance

Avito Cool Challenge 2018:D. Maximum Distance

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; }