题面
题意
- t 组样例,每组 n 个点,每个点上有权值,然后n-1条边把点连起来构成图(题中说是树)
- 有多种颜色可以给图中每条边染色( n-1条边最多染 n-1 种颜色),问染i种颜色,图的最大权值是多少
- 最大权值的计算 :删去所有颜色不为i的边之后,图中每个点数>1的连通块点权和的最大值。
定义图的权值为 i 种颜色的权值和。
题解
- 题目有点唬人啊,其实超级简单,读不懂题的多看几遍,或者看样例 ,还有注意数据范围 long long
- 我们先模拟一遍样例
可以发现,当只有一种颜色时,肯定是全选最大,当有两种颜色时,图肯定会分割,然后新增加一个连通块,增加的权值就是一个点的权值,三种颜色也是一样- 那么我们就可以,记录每个点 i 连接的边数,就是度 di,每染色一次,度数就会减少1,对应的图的权值就会增加 wi ,因为要求每次都是最大,所以我们将{w,d} 放入大根堆(按点的权值从到小排列),每次增加一种颜色,就从大根堆取一个最大的数,度数-1,如果度数不为0,就再仍回大根堆
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> PLL;
const int N = 2e5 + 10;
ll t, n;
ll w[N], d[N], res[N];
int main() {
cin >> t;
while (t--) {
cin >> n;
for (int i = 1; i <= n; i++) d[i] = 0, res[i] = 0;
ll sum = 0;
for (int i = 1; i <= n; i++) cin >> w[i], sum += w[i];
for (int i = 1; i < n; i++) {
ll a, b;
cin >> a >> b;
d[a]++, d[b]++;
}
priority_queue<PLL> qu;
for (int i = 1; i <= n; i++) {
d[i]--;
if (d[i]) qu.push({w[i], d[i]});
}
res[1] = sum;
for (int i = 2; i < n; i++) {
if (!qu.empty()) {
PLL x = qu.top();
qu.pop();
sum += x.first;
x.second--;
if (x.second) qu.push(x);
}
res[i] = sum;
}
for (int i = 1; i < n; i++) {
cout << res[i] << " ";
}
cout << endl;
}
return 0;
}