[最小生成树]洛谷 P9235 网络稳定性 题解
直入正题。一个贪心发现你要让最小的路径尽可能大,这样是不是一下想到最大生成树,一个 kruskal 搞定
生成完之后最优解肯定在这棵树里,所以直接做最小值就行。
然而还有一个问题就是查询的两个点有可能不连通,那咋办呢?维护森林很麻烦,于是建一个虚点,向所有点连一个边权极小的边,再在这个图上做生成树,这样如果两点不连通,求出的最小值就应该是我们设置的极小值,特判一下就行;
因为边权都是正的,因此极小值采用 0
理解题意后还算好写,维护 lca 同时维护一下路径最小值即可,也没啥注意事项
#include <bits/stdc++.h>
#define qwq return 0
#define int long long
const int N = 3e5 + 7;
const int M = 6e5 + 7;
namespace P9235 {
using namespace std;
int cnt , tot , n , m , q , head[N] , dep[N] , lca[N][20] , Min[N][20] , fa[N] , Head[N];
struct edge {
int u , v , w , n;
inline bool operator < (const edge &L) const {
return w > L.w;
}
}E[N + M] , e[N]; // 一个存原来的图,一个存生成树
inline void add(int f , int t , int w) {
E[++cnt].u = f , E[cnt].v = t , E[cnt].w = w , E[cnt].n = head[f];
head[f] = cnt;
}
inline void Add(int f , int t , int w) {
e[++tot].u = f , e[tot].v = t , e[tot].w = w , e[tot].n = Head[f];
Head[f] = tot;
}
inline int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
void dfs(int s , int fa , int W) {
dep[s] = dep[fa] + 1;
lca[s][0] = fa;
Min[s][0] = W;//类似lca求最小值
for(register int i = 1; (1 << i) <= dep[s]; ++i) {
lca[s][i] = lca[lca[s][i - 1]][i - 1];
Min[s][i] = min(Min[s][i - 1] , Min[lca[s][i - 1]][i - 1]);
}
for(register int i = Head[s]; i ; i = e[i].n) {
if(e[i].v != fa) {
dfs(e[i].v , s , e[i].w);
}
}
}
inline int query(int a ,int b) {
int res = 1e18;
if(dep[a] < dep[b]) {
swap(a , b);
}
for(register int i = 18; i >= 0; --i) {
if(dep[lca[a][i]] >= dep[b]) {
res = min(res , Min[a][i]);
a = lca[a][i];
}
}
if(a == b) {
return res;
}
for(register int i = 18; i >= 0; --i) {
if(lca[a][i] != lca[b][i]) {
res = min({res , Min[a][i] , Min[b][i]});
a = lca[a][i] , b = lca[b][i];
}
}
res = min({res , Min[a][0] , Min[b][0]});
return res;
}
void kk() {
for(register int i = 1; i <= cnt; ++i) {
int f = E[i].u , t = E[i].v;
int x = find(f) , y = find(t);
if(x != y) {
Add(f , t , E[i].w) , Add(t , f , E[i].w);
fa[x] = y;
}
}
}
void Kx() {
ios :: sync_with_stdio(0) , cin.tie(0) , cout.tie(0);
cin >> n >> m >> q;
for(register int i = 1; i <= m; ++i) {
int a , b , c; cin >> a >> b >> c;
add(a , b , c) , add(b , a , c);
}
for(register int i = 1; i <= n; ++i) {
fa[i] = i;
add(n + 1 , i , 0) , add(i , n + 1 , 0);//虚点
}
fa[n + 1] = n + 1;
sort(E + 1 , E + cnt + 1);
kk();
dep[0] = - 1;
dfs(n + 1 , 0 , 0);
while(q--) {
int x , y;
cin >> x >> y; int z = query(x , y);
cout << (z == 0 ? -1 : z) << '\n';
}
}
}
signed main() {
P9235 :: Kx(); qwq;
}