最大化根

Educational Codeforces Round 168 (Rated for Div. 2)
Maximize the Root

#树
#DFS
题意:给一颗树,每个节点都有一个值。
可以对节点进行操作:自身+1,子树所有节点-1(要求必须>0)
求根节点的最大值

由于对子树所有节点都进行-1操作,根节点能增加的值由其中最小值决定。
转化为操作后求子树将最小值最大化。考虑贪心
发现对于任意一颗树,如果它的根节点值大于其子树的最小值,这颗子树的最小值继承其子树的最小值
如果根节点的值小于其子树的最小值,考虑平均它们的值
从根进行DFS,则一定是自底向顶进行操作,这样可以使根节点的值最大化。

#include<bits/stdc++.h>
using ll = long long;
using namespace std;
#define dbg(x) cout<<#x<<" = "<<x<<endl
#define int long long 
int head[200001];
int to[200001];
int nx[200001];
int v[200001];
int cnt = 1;
void add(int x, int y) {
    to[cnt] = y;
    nx[cnt] = head[x];
    head[x] = cnt++;
}
int mi[2000001];
int dfs(int p) {
    if (mi[p] > 0) {
        return mi[p];
    }
    ll tmp = 1e18;
    for (int i = head[p]; i; i = nx[i]) {
        tmp = min(tmp, dfs(to[i]));
    }
    if(tmp == 1e18) { //叶子节点
        mi[p] = v[p];
    } else {
        if(tmp > v[p]) {
            int dis = tmp - v[p];
            mi[p] =v[p] + dis/2;
        } else {
            mi[p] = tmp;
        }
    }
    return mi[p];
}
void solve() {
    int n;
    cin >> n;
    cnt = 1;
    for (int i = 1; i <= n; i++) {
        head[i] = 0;
        mi[i] = 0;
    }
    for (int i = 1; i <= n; i++) cin >> v[i];
    for (int i = 2; i <= n; i++) {
        int y;
        cin >> y;
        add(y, i);
    }
    dfs(1);
    ll mini = 1e18;
    for(int i = head[1]; i; i= nx[i]) {
        mini = min(mini,mi[to[i]]);
    }
    cout<<mini + v[1]<<endl;
}
signed main() {
    int T;
    cin >> T;
    while (T--) {
        solve();
    }
}
github