这道题目我们可以考虑二分做,二分出最终的深度,然后尝试是否能使用不超过\(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;
}