题意:
给定一个有n个节点的树,你可以尝试以下操作k次
选择树的一条边(v,u),使v是u的父级。删除边(v,u)。增加一条边(1,u)(即让u及其子树成为根的孩子)。
树的高度是其顶点的最大深度,而顶点的深度是根到它的路径上的边数。例如,顶点1的深度是0,因为它是根,而它所有的子节点的深度是1。
要求输出可以达到的最小的树的高度是多少?
输入
第一行包含一个整数t(1≤t≤104)--测试用例的数量。每个测试案例的第一行包含两个整数n和k(2≤n≤2⋅105;0≤k≤n-1)--树中顶点的数量和你可以执行的最大操作数。
第二行包含n-1个整数p2,p3,...,pn(1≤pi<i)--第i个顶点的父级。顶点1是根。
所有测试案例的n之和不超过2⋅105。
输出
对于每个测试案例,打印一个整数--通过最多执行k次操作可以达到的最小的树的高度。
本题求最大深度最小化问题,首先考虑二分做法
auto check = [&](int x)->bool
{
int cnt = 0;
//由下往上
for (int i = 1; i <= n; i++)depth[i] = 1;
for (int i = n; i >= 2; i--)
{
for (auto t : e[i])
{
if (depth[t] == x)
{
cnt++; continue;
}
depth[i] = max(depth[i], depth[t] + 1);
}
}
return cnt <= k;
};
#include <bits/stdc++.h>
#define oo 0x3f3f3f3f
#define ll long long
#define IO ios::sync_with_stdio(0);cin.tie(0)
#define rep(i,a,n) for (ll i=a;i<=n;i++)
#define per(i,a,n) for (ll i=a;i>=n;i--)
#define fi first
#define se second
const int N = 2e5 + 10, M = 2 * N;
using namespace std;
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
#define deb(i,x) if(int i==x) int k = 1;
#define pb push_back
#define YES {puts("YES");return;}
#define NO {puts("NO"); return;}
#define all(x) x.begin(),x.end()
ll lowbit(ll x) { return x & -x; }
ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
ll qmi(ll a, ll b, ll mod) {
ll res = 1; while (b) { if (b & 1) res = res * a % mod; a = a * a % mod; b >>= 1; }
return res;
}
int mx = -oo;
vector<vector<int>> e(N);
void dfs(int p,int d)
{
for (auto x : e[p])
{
if (e[x].empty())
mx = max(mx, d + 1);
dfs(x, d + 1);
}
}
int depth[N];
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
IO;
int t; cin >> t;
while (t--)
{
int n, k; cin >> n >> k;
int v;
mx = -oo;
for (int i = 1; i <= n; i++)e[i].clear();
for (int i = 2; i <= n; i++)
{
cin >> v;
e[v].push_back(i);
}
dfs(1, 0);//得到最大深度,初始化r的范围
auto check = [&](int x)->bool
{
int cnt = 0;
for (int i = 1; i <= n; i++)depth[i] = 1;
for (int i = n; i >= 2; i--)
{
for (auto t : e[i])
{
if (depth[t] == x)
{
cnt++; continue;
}
depth[i] = max(depth[i], depth[t] + 1);
}
}
return cnt <= k;
};
int l = 1, r = mx;
//if (n > 1)l = 1; 注意题目给定的n是大于等于2的,所以l初始化为1即可,不需考虑0
while (l < r)
{
int mid = l + r >> 1;
if (check(mid))
r = mid;
else
l = mid + 1;
}
cout << l << endl;
}
return 0;
}