Good Bye 2020 D

Good Bye 2020 D

大意

略...

思路

(k=1) 时,答案就是点权之和, 记为 (sum_1)

考虑 (k=2) ,此时最大的方案是选择此时点权最大且以它为根时它的两个子树有相同颜色的点,对于 (k=2) 就是选择一个非叶子节点,

然后选择它的一个子树,将其全部染成一个颜色。此时答案为 (sum_1+val_{i})(val_i) 为选择的点的点权。

下述默认以选择的点为根

首先, (k=c) 的最优方案肯定将原树分为了恰好 (c) 个联通块,否则我们可以通过修改块的颜色(或交换)使联通块个数减少为 (c) 且答案更优。

(因为对于相同颜色的块只会考虑点权之和最大的那个)

其次每次 (k) 增加时会贪心选择此时图中可以选择的点中最大的点(题目要求),而根据上述,会选择该点的一颗子树,将其全部染色。

选择的点必须至少有两颗子树是相同的颜色,否则颜色个数会小于 (k)

(如果子树中有多种颜色,只将离选择的点最近的一部分颜色相同的点视为子树)

显然这是在考虑点的度

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;

#define ll long long
#define ull unsigned long long
#define cint const int&
#define Pi acos(-1)

const int mod = 998244353;
const int inf_int = 0x7fffffff;
const ll inf_ll = 0x7fffffffffffffff;
const double ept = 1e-9;

int t, n;
ll w[200100];
int deg[200100];
int q[200100], cnt;

int main() {
    ios::sync_with_stdio(false);
    cin >> t;
    while(t--) {
        cnt = 0;
        cin >> n;
        ll ans=0;
        for(int i=1; i<=n; i++) cin >> w[i], ans += w[i], deg[i] = 0;
        int f, t;
        for(int i=1; i<n; i++) {
            cin >> f >> t;
            ++deg[f]; ++deg[t];
            if(deg[f] > 1) q[++cnt] = w[f];
            if(deg[t] > 1) q[++cnt] = w[t];
        }
        sort(q+1, q+1+cnt);
        cout << ans << ' ';
        while(cnt) {
            ans += q[cnt--];
            cout << ans << ' ';
        }
        cout << endl;
    }
    return 0;
}

20min,-1

原文地址:https://www.cnblogs.com/ullio/p/14215977.html