【GMOJ3501】消息传递

题目

题目链接:https://gmoj.net/senior/#main/show/3501
H国的社会等级森严,除了国王之外,每个人均有且只有一个直接上级,当然国王没有上级。如果A是B的上级,B是C的上级,那么A就是C的上级。绝对不会出现这样的关系:A是B的上级,B也是A的上级。
最开始的时刻是0,你要做的就是用1单位的时间把一个消息告诉某一个人,让他们自行散布消息。在任意一个时间单位中,任何一个已经接到消息的人,都可以把消息告诉他的一个直接上级或者直接下属。
现在,你想知道:
1.到底需要多长时间,消息才能传遍整个H国的所有人?
2.要使消息在传递过程中消耗的时间最短,可供选择的人有那些?

思路

洛谷P2018是这道题的弱化版,复杂度\(O(n^2)\)即可过。

50pts

树形\(dp\)。分别枚举每一个点开始传递时的答案,然后取\(min\)。假设现在从\(i\)开始传递,那么我们设\(i\)为树根,要往叶子节点传递。
在以\(i\)为根的情况下,假设我们处理到以\(x\)为根的子树,设\(f[i]\)表示处理完\(i\)为根的子树的最少时间,那么显然应将\(x\)的儿子的\(f[i]\)从大到小的顺序传递。
那么有

\[f[x]=min_{y\in x's\ son}(f[y]+ord[y]) \]

其中\(ord[y]\)表示\(y\)的排名。
时间复杂度\(O(n^2\log n)\)

100pts

先求出\(1\)为根时的答案,接下来换根即可。
维护每一个点的前后缀\(max\),从\(x\to y\)时,将\(1\sim ord[y]-1\)\(min\)\(ord[y]+1\sim cntson[x]\)\(min-1\)\(min\)即可。
时间复杂度\(O(n\log n)\)

代码

#include <map>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N=200010;
int n,ans,tot,q[N],f[N],head[N],cnt[N];
vector<int> pos,maxn[N][3];
map<int,int> rk[N];

struct edge
{
	int next,to;
}e[N*2];

bool cmp(int x,int y)
{
	return f[x]>f[y];
}

void add(int from,int to)
{
	e[++tot].to=to;
	e[tot].next=head[from];
	head[from]=tot;
}

void solve(int x,int fa)
{
	cnt[x]=0;
	for (int i=head[x];~i;i=e[i].next)
		if (e[i].to!=fa) q[++cnt[x]]=e[i].to;
	sort(q+1,q+1+cnt[x],cmp);
	maxn[x][1].clear(); maxn[x][2].clear();
	maxn[x][1].push_back(0); maxn[x][2].push_back(0);
	for (int i=1;i<=cnt[x];i++)
	{
		maxn[x][1].push_back(max(maxn[x][1][i-1],f[q[i]]+i));
		rk[x][q[i]]=i;
	}
	for (int i=cnt[x];i>=1;i--)
		maxn[x][2].push_back(max(maxn[x][2][cnt[x]-i],f[q[i]]+i));
	maxn[x][1].push_back(0); maxn[x][2].push_back(0);
}

void dp(int x,int fa)
{
	for (int i=head[x];~i;i=e[i].next)
		if (e[i].to!=fa) dp(e[i].to,x);
	solve(x,fa);
	f[x]=maxn[x][1][cnt[x]];
}

void dfs(int x,int fa)
{
	if (x!=1)
	{
	//	printf("%d\n",rk[fa][x]);
		f[fa]=max(maxn[fa][1][rk[fa][x]-1],maxn[fa][2][cnt[fa]-rk[fa][x]]-1);
		solve(x,0);
		f[x]=maxn[x][1][cnt[x]];
		if (f[x]<ans)
		{
			pos.clear(); 
			ans=f[x]; pos.push_back(x);
		}
		else if (f[x]==ans) pos.push_back(x);
	}
	for (int i=head[x];~i;i=e[i].next)
		if (e[i].to!=fa) dfs(e[i].to,x);
	if (x!=1)
	{
		f[x]=max(maxn[x][1][rk[x][fa]-1],maxn[x][2][cnt[x]-rk[x][fa]]-1);
		f[fa]=maxn[fa][1][cnt[fa]];
	}
}

int main()
{
	freopen("news.in","r",stdin);
	freopen("news.out","w",stdout);
	memset(head,-1,sizeof(head));
	scanf("%d",&n);
	for (int i=2,x;i<=n;i++)
	{
		scanf("%d",&x);
		add(x,i); add(i,x);
	}
	dp(1,0);
	ans=f[1]; pos.push_back(1);
	dfs(1,0);
	sort(pos.begin(),pos.end());
	printf("%d\n",ans+1);
	for (int i=0;i<pos.size();i++)
		printf("%d ",pos[i]);
	return 0;
}
posted @ 2020-02-04 18:46  stoorz  阅读(202)  评论(0编辑  收藏  举报