1 条题解

  • 0
    @ 2025-8-24 22:54:35

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Nygglatho
    AFOed

    搬运于2025-08-24 22:54:35,当前版本为作者最后更新于2024-10-22 12:39:13,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    这和吉林 CPC B 题类似,考虑树形 DP。

    令:

    • dpx,0\mathit{dp}_{x,0} 表示节点 xx 选最多 kk 条边,以其为根的子树选择的边数最大值,valx,0\mathit{val}_{x,0} 表示在 dpx,0\mathit{dp}_{x,0} 最大情况需要的最小成本。
    • dpx,1\mathit{dp}_{x,1}dpx,0\mathit{dp}_{x,0} 其他一样,但是只能选择最多 k1k-1 条边,valx,1\mathit{val}_{x,1} 表示在 dpx,1\mathit{dp}_{x,1} 最大情况需要的最小成本。

    考虑当前节点 now\mathit{now} 选择连向其儿子的边,如果选择了 (now,v)(\mathit{now},v) 这条边,则 vvdpnow\mathit{dp}_\mathit{now} 的贡献为 dpv,1+1dp_{v,1}+1。因为 vv 连向其父亲节点也算作一条边。同样,vvvalnow\mathit{val}_{\mathit{now}} 的贡献为 valv,1+d\mathit{val}_{v,1}+d,其中 dd 是该边的边权。而如果不选择这条边,则对 dpnow\mathit{dp}_{\mathit{now}} 的贡献为 dpv,0dp_{v,0},对 valnow\mathit{val}_{\mathit{now}} 的贡献为 valv,0\mathit{val}_{v,0}

    显然你肯定要选择 dpv,1+1dpv,0\mathit{dp}_{v,1}+1-\mathit{dp}_{v,0} 尽量大的,如果相同就选择 valv,1+dvalv,0\mathit{val}_{v,1}+d-\mathit{val}_{v,0}dd 为边权)尽量小的。这样可以保证答案尽量大。按照这种方式进行排序,然后直接选择即可。

    int n, k;
    ll val[310000][2], dp[310000][2];
    ll a[310000];
    vector <pii> v[310000];
    vector <pii> _v;
    
    void dfs (int now) {
        ll s0 = 0ll, s1 = 0ll;
        ll vl0 = 0ll, vl1 = 0ll;
        ll mx = 0ll, mn = 0ll;
        _v.clear();
        for (auto [i, j] : v[now]) dfs (i);
        for (auto [i, j] : v[now]) _v.push_back({i, j}), vl0 += val[i][0], s0 += dp[i][0];
        sort (_v.begin(), _v.end(), [] (pii X, pii Y) {
            auto [x, _] = X; auto [y, __] = Y;
            if (dp[x][1] - dp[x][0] == dp[y][1] - dp[y][0]) return (_ + val[x][1] - val[x][0] < __ + val[y][1] - val[y][0]);
            return (dp[x][1] - dp[x][0] > dp[y][1] - dp[y][0]);
        });
        mx = s0, mn = vl0;
        dp[now][0] = dp[now][1] = mx;
        val[now][0] = val[now][1] = mn;
        int cnt = 0;
        for (auto [i, j] : _v) {
            ++ cnt;
            s0 -= dp[i][0], s1 += dp[i][1] + 1;
            vl0 -= val[i][0], vl1 += val[i][1] + j;
            mx = s0 + s1, mn = vl0 + vl1;
            if (cnt <= k) {
                if (mx > dp[now][0]) {
                    dp[now][0] = mx; val[now][0] = mn;
                } else if (mx == dp[now][0] && mn < val[now][0]) {
                    val[now][0] = mn;
                }
            }
    
            if (cnt <= k - 1) {
                if (mx > dp[now][1]) {
                    dp[now][1] = mx; val[now][1] = mn;
                } else if (mx == dp[now][1] && mn < val[now][1]) {
                    val[now][1] = mn;
                }
            }
        }
        _v.clear();
    }
    
    int main() {
        cin >> n >> k;
        F (i, 2, n) {
            int p;
            cin >> p >> a[i];
            v[p].push_back({i, a[i]});
        }
        dfs (1);
        cout << dp[1][0] << ' ' << val[1][0] << '\n';
    }
    
    • 1

    信息

    ID
    9021
    时间
    1000ms
    内存
    256MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者