走廊泼水节

// 走廊泼水节.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

/*
https://www.acwing.com/problem/content/348/
给定一棵 N 个节点的树,要求增加若干条边,把这棵树扩充为完全图,并满足图的唯一最小生成树仍然是这棵树。

求增加的边的权值总和最小是多少。

注意: 树中的所有边权均为整数,且新加的所有边权也必须为整数。

输入格式
第一行包含整数 t,表示共有 t 组测试数据。

对于每组测试数据,第一行包含整数 N。

接下来 N−1 行,每行三个整数 X,Y,Z,表示 X 节点与 Y 节点之间存在一条边,长度为 Z。

输出格式
每组数据输出一个整数,表示权值总和最小值。

每个结果占一行。

数据范围
1≤N≤6000
1≤Z≤100
输入样例:
2
3
1 2 2
1 3 3
4
1 2 3
2 3 4
3 4 5


2
5
1 2  6
2 3  5
2 4  9
4 5  3

3
1 2  9
2 3  10

输出样例:
4
17
*/
#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 6000 + 10;
int f[N];
long long setlen[N];

int n;
struct Edge {
	int u, v, w;
	bool operator<(const Edge& e) const {
		return w < e.w;
	}
}edges[N];

int T;

int find(int x) {
	if (x != f[x]) f[x] = find(f[x]);
	return f[x];
}

void init() {
	for (int i = 0; i < N; i++) {
		f[i] = i;
		setlen[i] = 1;
	}
}

void solve() {
	cin >> n;
	init();
	for (int i = 0; i < n-1; i++) {
		cin >> edges[i].u >> edges[i].v >> edges[i].w;
	}
	sort(edges,edges+n-1);
	long long ans = 0;
	for (int i = 0; i < n - 1; i++) {
		int a = edges[i].u, b = edges[i].v, w = edges[i].w;
		int fa = find(a), fb = find(b);
		if (fa != fb) {
			ans += (1ll*setlen[fa]*setlen[fb] -1) * (w + 1);
			f[fa] = fb;
			setlen[fb] += setlen[fa];
		}
	}

	cout << ans << endl;
}

     
int main() {
	cin >> T;
	while (T--) {
		solve();
	}
	return 0;
}

posted on 2025-04-21 12:05  itdef  阅读(10)  评论(0)    收藏  举报

导航