3501. 【NOIP2013模拟联考15】消息传递

Description

H国的社会等级森严,除了国王之外,每个人均有且只有一个直接上级,当然国王没有上级。如果A是B的上级,B是C的上级,那么A就是C的上级。绝对不会出现这样的关系:A是B的上级,B也是A的上级。

最开始的时刻是0,你要做的就是用1单位的时间把一个消息告诉某一个人,让他们自行散布消息。在任意一个时间单位中,任何一个已经接到消息的人,都可以把消息告诉他的一个直接上级或者直接下属。

现在,你想知道:

1.到底需要多长时间,消息才能传遍整个H国的所有人?

2.要使消息在传递过程中消耗的时间最短,可供选择的人有那些?

Input

输入文件的第一行为一个整数N(N≤200000),表示H国人的总数,假如人按照1到n编上了号码,国王的编号是1。

第2行到第N行(共N-1行),每一行一个整数,第i行的整数表示编号为i的人直接上级的编号。

Output

输出共计两行:

第一行为一个整数,表示最后一个人接到消息的最早时间。

第二行有若干个数,表示可供选择人的编号,按照编号从小到大的顺序输出,中间用一个空格隔开。

Sample Input

输入1:

4
1
1
1

输入2:

8
1
1
3
4
4
4
3

Sample Output

输出1:

4
1 2 3 4

输出2:

5
3 4 5 6 7

Data Constraint

对于20%的数据,满足N<=3000;

对于50%的数据,满足N<=20000;

对于100%的数据,满足N<=200000;

Solution

树形dp。

设f[i]表示处理完以i为根的子树后的最小时间,f[i]=max(f[i],f[j]+rank[j]})~(~j\in son~)rank[j]表示j的f值在所有i的儿子中从小到大排第几。

那么考虑换根dp,设g[i]表示除去i这棵子树后,(其他部分)以i的父亲为根的整棵树的答案。

那么换根时,我们将i自己的g值和所有儿子的f值一起排序后,得到rank数组,然后再用上面的式子,就可以求出换根后以i为根的答案了。最后的问题是如何求g,因为在求i的答案时,g[i]必须已经求出,所以应该从通过i求出每个儿子的g值,那么我们将所有的儿子和自己的g值排序后,考虑删掉中间的一个x后的答案,那么这个时候x以前的数的rank不变,而x后面的数的rank要-1,所以我们预处理出一个前缀max和后缀max,表示前i个(或后i个)数中f[j]+rank[j]的最小值,那么j的g值就可以从max(pre[x-1],suf[x+1]-1)转移过来。

Code

#include<cstdio> 
#include<cstring>
#include<algorithm>
#define I int
#define ll long long
#define F(i,a,b) for(register I i=a;i<=b;++i)
#define Fd(i,a,b) for(register I i=a;i>=b;--i)
#define mem(a,b) memset(a,b,sizeof a)
#define N 200005
using namespace std;
I n,x,t[N<<1],nx[N<<1],l[N],suf[N],pre[N],f[N],tot,ans[N],answer,g[N];
struct SON{I x,v;}s[N];
void rd(I &x){
	x=0;char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
}
void A(I x,I y){t[++tot]=y,nx[tot]=l[x],l[x]=tot;}
I cmp(SON x,SON y){return x.v>y.v;}
I cmp2(I x,I y){return x<y;}
void dg(I x,I y){
	for(I k=l[x];k;k=nx[k]) if(y!=t[k]) dg(t[k],x);
	tot=0;
	for(I k=l[x];k;k=nx[k]) if(y!=t[k]){s[++tot]=SON{t[k],f[t[k]]};}
	sort(s+1,s+1+tot,cmp);
	F(i,1,tot) f[x]=max(f[x],s[i].v+i);
}
void getans(I x,I y){
	tot=0;
	if(x!=1) s[++tot]=SON{-1,g[x]};
	for(I k=l[x];k;k=nx[k]) if(t[k]!=y) s[++tot]=SON{t[k],f[t[k]]};
	sort(s+1,s+1+tot,cmp);
	pre[0]=suf[tot+1]=0;
	F(i,1,tot) pre[i]=max(pre[i-1],s[i].v+i);
	Fd(i,tot,1) suf[i]=max(suf[i+1],s[i].v+i-1);
	F(i,1,tot) if(s[i].x>0) g[s[i].x]=max(pre[i-1],suf[i+1]);
	if(answer>pre[tot]){answer=pre[tot],ans[0]=0;}
	if(answer==pre[tot]) ans[++ans[0]]=x;
	for(I k=l[x];k;k=nx[k]) if(y!=t[k]) getans(t[k],x);
}
I main(){
	freopen("news.in","r",stdin);
	freopen("news.out","w",stdout);
	rd(n);
	F(i,2,n){rd(x);A(x,i);A(i,x);}
	dg(1,0);
	answer=N+1;
	getans(1,0);
	sort(ans+1,ans+1+ans[0],cmp2);
	printf("%d\n",answer+1);
	F(i,1,ans[0]) printf("%d ",ans[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zsjzliziyang/article/details/104199659