Educational Codeforces Round 136 (Rated for Div. 2) D. Reset K Edges
这道题目我们可以考虑二分做,二分出最终的深度,然后尝试是否能使用不超过\(k\)次操作使得深度符合条件。
考虑如何和判断,我们可以从根节点开始搜索,如果当前点的深度为\(mid + 1\),就对当前点进行操作。但很可惜,这种贪心方法可以很容易的举出反例,比如深度为\(mid\)的点下面有很多个叶子,此时不应该是修改叶子,而是修改深度为\(mid\)的点更优。
考虑反过来贪心,如果我们从叶子开始搜索,如果当前的点的深度为\(mid - 1\)且父节点不是根,则把当前点插到根上。
注意到题目保证了\(p_i < i\),所以我们直接倒序枚举就好了。
#include<bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
const int mod = 1e9 + 7;
void solve() {
int n, k;
cin >> n >> k;
vector<int> p(n + 1);
for (int i = 2; i <= n; i++)
cin >> p[i];
int l = 1, r = n - 1, res = -1;
while (l <= r) {
int mid = (l + r) / 2, cnt = 0;
vector<int> dis(n + 1);
for (int i = n; i > 1; i--) {
if (dis[i] == mid - 1 and p[i] != 1) cnt++;
else dis[p[i]] = max(dis[p[i]], dis[i] + 1);
}
if (cnt <= k) res = mid, r = mid - 1;
else l = mid + 1;
}
cout << res << "\n";
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
cin >> T;
while (T--)
solve();
return 0;
}