• Codeforces Round #646 (Div. 2) E. Tree Shuffling(树上dp)


    题目链接:https://codeforces.com/contest/1363/problem/E

    题意

    有一棵 $n$ 个结点,根为结点 $1$ 的树,每个结点有一个选取代价 $a_i$,当前 $b_i$,目标数字 $c_i$ 。每次可以选择以一个结点为根节点的子树中的 $k$ 个结点交换它们的 $b_i$,总代价为 $k imes a_{root}$ ,判断能否把所有结点都变为目标数字以及最小代价。

    题解

    因为每棵子树都可以被包含进更大的子树中,所以对于每棵子树的根节点,它的最小选取代价可以取它自身和所有可能的父节点的最小值。

    计算每棵子树中需要交换的 $0$ 和 $1$ 的个数,用根节点的最小选取代价交换后,多余的 $0$ 或 $1$ 累加至父节点所在的子树即可。

    代码

    #include <bits/stdc++.h>
    using ll = long long;
    using namespace std;
    const int N = 2e5 + 10;
    
    vector<int> G[N];
    int a[N], b[N], c[N];
    int cnt[N][2];
    ll ans;
    
    void dfs(int u, int pre) {
        if (pre != 0) a[u] = min(a[u], a[pre]);
        for (auto v : G[u]) {
            if (v != pre) {
                dfs(v, u);
                cnt[u][0] += cnt[v][0];
                cnt[u][1] += cnt[v][1];
            }
        }
        if (b[u] != c[u]) cnt[u][b[u]]++;
        int mi = min(cnt[u][0], cnt[u][1]);
        ans += 2LL * mi * a[u];
        cnt[u][0] -= mi;
        cnt[u][1] -= mi;
    }
    
    int main() {
        int n; cin >> n;
        for (int i = 1; i <= n; i++)
            cin >> a[i] >> b[i] >> c[i];
        for (int i = 0; i < n - 1; i++) {
            int u, v; cin >> u >> v;
            G[u].push_back(v);
            G[v].push_back(u);
        }
        dfs(1, 0);
        cout << ((cnt[1][0] or cnt[1][1]) ? -1 : ans) << "
    ";
    }

    参考博客:https://www.cnblogs.com/axiomofchoice/p/13022886.html

  • 相关阅读:
    求欧拉路径模版 fleury算法
    回学校前的计划
    高斯消元模版
    usaco 3.2 Stringsobits 数位dp
    dijkstra模版
    codeforces AIM Tech Round (Div. 2)
    bnuoj 51275 并查集按深度合并建树
    bzoj3674: 可持久化并查集
    poj2104 求区间第k大 可持久化线段树
    Miller_Rabin判断素数模版
  • 原文地址:https://www.cnblogs.com/Kanoon/p/13024219.html
Copyright © 2020-2023  润新知