CF1436D
我们来看一下此题:
看到最大值最小,很容易想到二分答案,设二分的值为 $x$
再设 $sum_i$ 是 $i$ 的子树中 $a_j$ 的和,$l_i$ 表示 $i$ 的子树中叶子结点的个数,
那么我们假设在点 $u$ 上,且 $u$ 的子树除了 $u$ 以外全部分配完成,那么 $u$ 上的人肯定会优先去人比较少的叶子节点,
那么如果目前合法,$u$ 不合法当且仅当 $x < \left\lceil\dfrac{sum_{u}}{l_u}\right\rceil$,
时间复杂度:$O(n log n)$
其实可以不用二分,直接取 $\left\lceil\dfrac{sum_{u}}{l_u}\right\rceil$ 的最大值即可
时间复杂度:$O(n)$
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
#define int long long // 别忘开 long long
const int maxn = 2e5 + 10;
struct node {
int to, nxt;
} edge[maxn << 1];
int cnt, head[maxn];
int ans = 0, a[maxn], l[maxn], sum[maxn];
void add (int u, int v) { // 建边
cnt ++;
edge[cnt].to = v;
edge[cnt].nxt = head[u];
head[u] = cnt;
}
void dfs (int u, int f) {
sum[u] = a[u];
int son = 0;
for (int i = head[u]; i; i = edge[i].nxt) {
int v = edge[i].to;
if (v == f) continue;
dfs (v, u);
son ++;
l[u] += l[v]; sum[u] += sum[v];
}
if (son == 0) l[u] = 1;
int res = sum[u] / l[u];
if (res * l[u] < sum[u]) res ++;
ans = max (ans, res); // 取最大值
}
signed main() {
int n; scanf ("%lld", &n);
for (int i = 2; i <= n; ++i) {
int x; scanf ("%lld", &x);
add (x, i); add (i, x);
}
for (int i = 1; i <= n; ++i) scanf ("%lld", &a[i]);
dfs (1, 0);
printf ("%lld", ans);
return 0;
}