思路:
二分答案。我们可以把所有儿子结点的数目存到一个vector里面,然后按照从大到小排序,肯定贪心的先染儿子数量多的点。如何写check?假如需要x轮完成染色,当前实际需要need轮,那么至少需要need += vector.size() + 1轮,1是染根节点,vector.size()是保证每个结点的儿子节点至少有一个被染色,然后我们贪心先染色儿子数目多的。假如是第i + 1轮开始染色,那么到x轮结束,它一共有1 + x - i - 1个儿子被染色,如果这个值比实际儿子数量多,则需要 need += q[i] - (x - i)轮,最后如果need比x小就return true, 反之 return false。
bool check(int x){
int need = m + 1;
for(int i = 0; i < m; i ++ ){
need += max(0, (q[i] - 1) - (x - i - 1));
}
return need <= x;
}
void solve()
{
scanf("%d",&n);
for(int i = 1; i <= n; i ++ ) du[i] = 0;
q.clear();
for(int i = 1; i <= n - 1; i ++ ){
int x;
scanf("%d",&x);
du[x] ++;
}
for(int i = 1; i <= n; i ++ ){
if(du[i]) q.pb(du[i]);
}
sort(all(q), greater<int>());
m = sz(q);
int l = 0, r = n;
while(l < r){
int mid = l + r >> 1;
if(check(mid)) r = mid;
else l = mid + 1;
}
printf("%d\n",l);
}