测评会员优惠活动进行中 · 开通 VIP,有效期内测评不限次 VIP 优惠中 · 测评不限次 立即查看

A23831. 最小生成树

填空题 困难

题目描述

最小生成树

题目描述

给定一张包含 n个结点m 条边的带权连通无向图,结点依次以1,2,..., n编号,第 i条边(    1≤i≤m)连接结点ui与结点vi ,边权为 wi

对于每条边,请你求出从图中移除该条边后,图的最小生成树中所有边的边权和。特别地,若移除某条边后图的最小生成树不存在,则输出-1 。

输入格式

第一行,两个正整数n,m ,分别表示图的结点数与边数。

接下来 行中的第i 行(1≤i≤m)包含三个正整数 ui,vi, wi,表示图中连接结点ui 与结点vi 的边,边权为wi

输出格式

输出共m 行,第i 行(1≤i≤m)包含一个整数,表示移除第 i条边后,图的最小生成树中所有边的边权和。若移除第 i条边后图的最小生成树不存在,则输出 -1。

样例

输入样例 1

5 5
1 2 4
2 3 3
3 4 1
2 5 2
3 1 8

输出样例 1

14
15
-1
-1
10

输入样例 2

6 10
1 2 6
2 3 3
3 1 4
3 4 5
4 5 8
5 6 2
6 4 1
3 2 4
5 4 4
3 3 6

输出样例 2

15
16
17
-1
15
17
18
15
15
15

数据范围

子任务编号	测试点占比	    n	    m	        特殊性质
      1	    20%    	        ≤50	≤100	          -
      2	    30%        	    ≤10⁵   ≤10⁵	         n = m
      3	    30%	            ≤500≤2×10⁴             -
      4	    20%            	≤10⁵   ≤10⁵             -      

对于所有测试点,保证1≤n≤105 ,1≤m≤105 , 1≤ ui,vi≤n,1≤wi≤109

参考答案

#include <cstdio> #include <algorithm> using namespace std; const int N = 1e5 + 5; const int M = 2e5 + 5; const long long oo = 1e18; int n, m; int u[M], v[M], w[M], p[M]; int h[N], id[M], nx[M], et; int f[N], mark[M]; long long s, ans[M]; int dep[N], pid[N]; bool cmp(int x, int y) { return w[x] < w[y]; } int getf(int u) { return f[u] ? f[u] = getf(f[u]) : u; } void link(int x, int p) { id[++et] = p; nx[et] = h[x]; h[x] = et; } void dfs(int x, int f=0, int p=0) { dep[x] = dep[f] + 1; pid[x] = p; for (int i = h[x]; i; i = nx[i]) { int to = u[id[i]] ^ v[id[i]] ^ x; if (to != f) dfs(to, x, id[i]); } } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= m; i++) { scanf("%d%d%d", &u[i], &v[i], &w[i]); p[i] = i; } sort(p + 1, p + m + 1, cmp); for (int i = 1; i <= m; i++) { int x = u[p[i]], y = v[p[i]]; if (getf(x) == getf(y)) continue; mark[p[i]] = 1; f[getf(x)] = y; s += w[p[i]]; link(x, p[i]); link(y, p[i]); } for (int i = 1; i <= m; i++) ans[i] = mark[i] ? oo : s; dfs(1); for (int i = 1; i <= n; i++) f[i] = 0; for (int i = 1; i <= m; i++) { if (mark[p[i]]) continue; int x = getf(u[p[i]]), y = getf(v[p[i]]); while (x != y) { if (dep[x] < dep[y]) x ^= y ^= x ^= y; int to = u[pid[x]] ^ v[pid[x]] ^ x; ans[pid[x]] = s - w[pid[x]] + w[p[i]]; f[x] = to; x = getf(x); } } for (int i = 1; i <= m; i++) printf("%lld\n", ans[i] < oo ? ans[i] : -1); return 0; }
上一题 下一题