1. 程式人生 > 實用技巧 >Good Bye 2020 D

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