Codeforces Global Round 23D. Paths on the Tree(树形dp + 贪心)

90 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第16天,点击查看活动详情
本文已参与「新人创作礼」活动,一 起开启掘金创作之路。

题目

image.png 中文大意

给我们n个结点形成的树每个节点都有一个价值s[i]s[i]每经过这一结点我们都会获得一次s[i]s[i]我们有k次机会从根节点走到叶结点但是一个结点的所以子结点经历过的次数最多与最小与最小的差值不能超过1问我们k次机会能获得的最大价值是多少

解法

如果这个结点现在有nn次机会走它有mm个子节点所以每个子节点最少能分到(n/m)(n/m)次机会剩下的(n(n %m) m)次机会都会分给能产生最大价值子节点也就是说明这些子节点会比其它子节点多一个机会所以对于一些根节点的所以子节点我们只需要将他们如果加一次机会产生的价值排序即可

int dfs(int x,int cnt) {
    res += s[x] * cnt;
    if(!v[x].size()) return s[x];
    priority_queue<int> q;
    for(auto u : v[x]) q.push(dfs(u,cnt/v[x].size()));
    int t = cnt % v[x].size();
    while(t--) {
        res += q.top(),q.pop();
    }
    return q.top() + s[x];
}

我们的cnt是我们至少能获得的机会如果我们再获得一次机会时我们产生的价值是s[x]+s[x]+他的子节点的第cnt+1cnt + 1大的值其他的同理

int p[N],s[N];
int res = 0;
vector<int> v[N];
int dfs(int x,int cnt) {
    res += s[x] * cnt;
    if(!v[x].size()) return s[x];
    priority_queue<int> q;
    for(auto u : v[x]) q.push(dfs(u,cnt/v[x].size()));
    int t = cnt % v[x].size();
    while(t--) {
        res += q.top(),q.pop();
    }
    return q.top() + s[x];
}
void solve()
{
   int n,k; cin >> n >> k;
   rep(i,n) v[i].clear();
   for(int i = 2; i <= n; i++) cin >> p[i],v[p[i]].pb(i);
   rep(i,n) cin >> s[i];
   res = 0;
   dfs(1,k) ;
   cout << res << endl;
}