Codeforce 1436D

题目链接

题目大意:
一棵树,树上每个节点保存有一个权值,结点的权值自上而下向下传递,直到叶子节点。传递的过程可以传递给多个子节点其中的一个或者多个。求最后各个叶子节点的权值的最大值最小是多少。(传递后,各子节点权值增加对应的值,父节点权值减去相应的值)

思路:
从根节点开始考虑,如果以根节点为根的子树上所有的叶子节点最后可以平分,则答案显然是 s u m ( i ) / l e a v e s ( i ) + ( s u m ( i ) % l e a v e s ( i ) ? 1 : 0 ) sum(i)/leaves(i) + (sum(i) \% leaves(i) ?1:0) sum(i)/leaves(i)+(sum(i)%leaves(i)?1:0)

如果不能平分,一定是有至少一个子树的权值很大,所以只需要将所有的权值分到其他的几个子树,权值大的子树不予划分,并且即便是划分后,权值最大的子树的权值依然是最大的,不会有比它更大的,这就又回到了第一个情况。

综上,只需要对每个点求解一次上述的值,取一个最大值就可行了。显然需要先求每个点为根的子树的权值和以及叶子个数。可以DFS求,也可树形dp求。

#include <bits/stdc++.h>
template<class T>
T max(T a, T b){
    
    
    return a > b ? a : b;
}
template<class T, class ... R>
T max(T a, T b, R ... c){
    
    
    T ans = max(a, b);
    return max(ans, c...);
}
typedef long long ll;
ll *a, *p, *siz;
ll n;
int main(){
    
    
    scanf("%lld", &n);
    a = (ll*)malloc((n + 10) * sizeof(ll));
    p = (ll*)malloc((n + 10) * sizeof(ll));
    siz = (ll*)malloc((n + 10) * sizeof(ll));
    for (int i = 1; i <= n; i++){
    
    
        siz[i] = 1;
    }
    p[1] = 0;
    for (int i = 2; i <= n; i++){
    
    
        scanf("%lld", (p + i));
        siz[p[i]] = 0;
    }
    for (int i = 1; i <= n; i++){
    
    
        scanf("%lld", (a + i));
    }
    ll ans = -1;
    for (int i = n; i >= 1; i--){
    
    
        ans = max(ans, a[i] / siz[i] + (a[i] % siz[i] ? 1 : 0));
        siz[p[i]] += siz[i];
        a[p[i]] += a[i];
    }
    printf("%lld\n", ans);
    free(a);
    free(p);
    free(siz);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43701790/article/details/109562609