题目大意:
一棵树,树上每个节点保存有一个权值,结点的权值自上而下向下传递,直到叶子节点。传递的过程可以传递给多个子节点其中的一个或者多个。求最后各个叶子节点的权值的最大值最小是多少。(传递后,各子节点权值增加对应的值,父节点权值减去相应的值)
思路:
从根节点开始考虑,如果以根节点为根的子树上所有的叶子节点最后可以平分,则答案显然是 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;
}