[CF1399E1] Weights Division

[CF1399E1] Weights Division - 贪心,堆

Description

给定一棵以 1 为根的带权树,一条路径的权值为边的权值之和,你可以进行一系列的操作,操作零次或多次。对于每次操作,你可以选择任意一条边,将其权值除以 2,找到最小操作数,以满足所有从根到叶子的路径的权值之和不超过 S。

Solution

因为要求的是和,所以可以贪心处理

预处理每条边出现次数,所有边扔到堆中,每次取最大的 (w-w/2)c,其中 c 为出现次数,然后再扔回堆中

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 1000005;

int n, s;
vector<pair<int, int>> g[N];
int w[N], siz[N];

void dfs1(int p, int from)
{
    siz[p] = 0;
    for (auto [q, wei] : g[p])
        if (q != from)
        {
            w[q] = wei;
            dfs1(q, p);
            siz[p] += siz[q];
        }
    siz[p] = max(siz[p], 1ll);
}

void solve()
{
    cin >> n >> s;
    for (int i = 1; i <= n; i++)
        g[i].clear(), w[i] = siz[i] = 0;
    for (int i = 1; i < n; i++)
    {
        int u, v, w;
        cin >> u >> v >> w;
        g[u].push_back({v, w});
        g[v].push_back({u, w});
    }
    dfs1(1, 0);
    struct item
    {
        int w;
        int c;
        void cut()
        {
            w = w / 2;
        }
        int eval() const
        {
            return c * (w - w / 2);
        }
        bool operator<(const item &rhs) const
        {
            return eval() < rhs.eval();
        }
    };
    priority_queue<item> heap;
    int ans = 0;
    int sum = 0;
    for (int i = 2; i <= n; i++)
    {
        heap.push({w[i], siz[i]});
        sum += w[i] * siz[i];
    }
    while (sum > s)
    {
        auto cur = heap.top();
        heap.pop();
        sum -= cur.eval();
        cur.cut();
        heap.push(cur);
        ans++;
    }
    cout << ans << endl;
}

signed main()
{
    ios::sync_with_stdio(false);

    int t;
    cin >> t;
    while (t--)
    {
        solve();
    }
}
原文地址:https://www.cnblogs.com/mollnn/p/14383954.html