[最小生成树]洛谷 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;
}
posted @ 2025-03-20 22:13  「癔症」  阅读(48)  评论(0)    收藏  举报