HDU 5242 Game 树链剖分

原题链接

文章目录

题意

给一棵树,每个节点都有一个权值,每次操作从根节点开始到叶子节点,问k次操作,最多可以取多少。

分析

因为答案是对树链求和统计,所以可以考虑树剖,也是考虑去剖重链(根据权值),最后只要沿着重儿子一路统计出所有的链的值,在从大到小排个序取k个就可以了。想到树剖之后就是相当板子的题了。

AC Code

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <string>
#include <set>
#include <map>
#include <bitset>
#define fi first
#define se second
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 5e5 + 10, M = 5e5 + 10, INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int n, m, cnt, k, h[N];
ll dp[N], f[N], son[N], a[N];

struct Edge {
    
    
    int to, next;
}e[M];
void add(int u, int v) {
    
    
    e[cnt].to = v;
    e[cnt].next = h[u];
    h[u] = cnt++;
}
void dfs1(int u, int fa) {
    
    
    son[u] = 0; f[u] = a[u];
    for (int i = h[u]; ~i; i = e[i].next) {
    
    
        int v = e[i].to;
        if (v == fa) continue;
        dfs1(v, u);
        if (f[son[u]] < f[v] || !son[u]) son[u] = v;
    }
    if (son[u]) f[u] += f[son[u]];
}

void dfs2(int u, int fa, int t) {
    
    
    dp[t] += a[u];
    if (son[u]) {
    
    
        dfs2(son[u], u, t);
    }
    for (int i = h[u]; ~i; i = e[i].next) {
    
    
        int v = e[i].to;
        if (son[u] == v || v == fa) continue;
        dfs2(v, u, v);
    }
}

void solve() {
    
    
    int T, C = 0; cin >> T; while (T--) {
    
    
        cin >> n >> k; cnt = 0;
        for (int i = 1; i <= n; i++) cin >> a[i], h[i] = -1, dp[i] = f[i] = 0;
        for (int i = 1; i <= n-1; i++) {
    
    
            int u, v; cin >> u >> v;
            add(u, v), add(v, u);
        }
        dfs1(1, 0);
        dfs2(1, 0, 1);
        sort(dp+1, dp+n+1);
        reverse(dp+1, dp+n+1);
        ll ans = 0;
        for (int i = 1; i <= k; i++) ans += dp[i];
        printf("Case #%d: %lld\n", ++C, ans);
    }
}

int main() {
    
    
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/kaka03200/article/details/111560028