传送门
把aia_iai看成faifa_ifai,建出一棵多叉树,再把多叉树转成二叉树,转出来的每棵二叉树对应着一种比赛方式。
以n=8,a2,...,8=1,1,2,4,3,3,3n=8,a_{2,...,8}=1,1,2,4,3,3,3n=8,a2,...,8=1,1,2,4,3,3,3为例,
多叉树转出的二叉树深度=赛程二叉树的深度
考虑求多叉树转二叉树后的最小可能深度:
假设uuu的所有儿子vvv的子树都已经转化好了:
现在要把uuu的子树转成二叉树:
设dep[x]dep[x]dep[x]表示以xxx为根的子树转成二叉树后的最小可能深度。
要求dep[u]dep[u]dep[u],我们要找到一种排列uuu的所有儿子vvv的方式,使得max{dep[v1]+1,dep[v2]=2,...,dep[vk]+k}max\{dep[v_1]+1,dep[v_2]=2,...,dep[v_k]+k\}max{dep[v1]+1,dep[v2]=2,...,dep[vk]+k}最小。
显然把儿子按depdepdep从大到小排序即可。
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int N=1e5+10;
vector<int> g[N];
int n,fa[N],mxd[N];
bool cmp(int a,int b){return mxd[a]>mxd[b];
}
void dfs(int u){int tot=g[u].size();for(int i=0;i<tot;i++) dfs(g[u][i]);sort(g[u].begin(),g[u].end(),cmp);if(tot){for(int i=0;i<tot;i++){int v=g[u][i];mxd[u]=max(mxd[u],mxd[v]+i+1);}}
}
int main(){scanf("%d",&n);for(int i=2;i<=n;i++){scanf("%d",&fa[i]);g[fa[i]].push_back(i);}dfs(1);printf("%d\n",mxd[1]);return 0;
}