解题思路
首先可以想到暴力每一个点作为根,求最小的传递时间。
设f[i]表示某点以i号边连向的子树中所有节点都被传递到消息的最短时间。易得:
考虑贪心,让
f
i
f_i
fi的孩子中消耗时间最大的先被传递,所以我们可以把
f
j
f_j
fj从大到小排序,
o
r
d
e
r
order
order表示f_j在序列中排在第几位(因为要依次传给每个儿子),这样
f
j
+
o
r
d
e
r
j
f_j+order_j
fj+orderj就表示爸爸以
j
j
j这条边连向的子树全部被传递所需时间,这样
f
i
f_i
fi为
f
j
f_j
fj中最大值,也是一个恒定的值。求出f_i后返回值给他的爸爸,他的爸爸得到了他所有儿子的消耗时间,把消耗时间排序…接着按照以上的思路。。
讲的好像不是很清楚啊, s o r r y sorry sorry…
代码
#pragma GCC optimize("3")
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<queue>
using namespace std;
int n,x,k,ans,t,w[200010],head[200010],p[200010],f[200010];
struct c{
int x,next;
}a[400010];
void add(int x,int y){
a[++k].x=y;
a[k].next=head[x];
head[x]=k;
}
int dfs(int x,int fa,int v){
if(f[v]&&v)return f[v];
int res=0;
priority_queue<int>q;
for(int i=head[x];i;i=a[i].next)
{
int y=a[i].x;
if(y!=fa)
q.push(dfs(y,x,i));//从大到小排序
}
for(int i=1;!q.empty();q.pop(),i++)
res=max(res,q.top()+i);//计算消耗时间并求max
return f[v]=res;
}
int main(){
freopen("news.in","r",stdin);
freopen("news.out","w",stdout);
scanf("%d",&n);
for(int i=2;i<=n;i++)
{
scanf("%d",&x);
add(i,x);add(x,i);
}
ans=2137383600;
for(int i=1;i<=n;i++)
{
p[i]=dfs(i,0,0)+1;
if(p[i]<ans)
ans=p[i];
}
printf("%d\n",ans);
for(int i=1;i<=n;i++)
if(p[i]==ans)
printf("%d ",i);
}