【Codeforces#596】D. Tree Factory

Description

传送门

  • 一个爷爷非空的节点x可以做一个操作:fa(x)=fa(fa(x))
  • 给一棵树,求如何将一条链通过最少的操作次数变成这个树,节点编号要完全一致。
  • 输出这条链初始的编号,以及操作次数,和每一次操作的节点编号。
  • n<=1e5

Solution

  • 构造题。
  • 思路比较神奇。首先反过来,求树变成链。
  • 首先考虑最少的操作次数。从树的深度切入。
  • 最初的深度是dep,最终的深度是n,每一次最多让深度加一。
  • 那么答案的下限就是n-dep。
  • 能不能有一种方案达到这个下限呢?实际上是有的。
  • 考虑对于最长链,找到上面的最深的分叉点,在这里断开。
  • 将最长链所在的儿子接到任意一个其他的儿子上,那么深度就一定会增加1。
  • 可以证明如果没有分叉点的话一定已经是一条链了。
  • 这样O(n)构造一波就好了。从最深点往上遍历各个子树。
  • 这种构造题先找答案下限再去满足的套路要熟悉运用。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define maxn 100005
using namespace std;

int n,m,i,j,k,mxdep,dep[maxn],fa[maxn],cnt[maxn];
int x,d[maxn],vis[maxn],tot,ans[maxn];
int em,e[maxn],nx[maxn],ls[maxn];

void insert(int x,int y){
	em++; e[em]=y; nx[em]=ls[x]; ls[x]=em;
	cnt[x]++;
}

int main(){
	scanf("%d",&n);
	dep[0]=1;
	for(i=1;i<n;i++) {
		scanf("%d",&fa[i]),dep[i]=dep[fa[i]]+1;
		x=(dep[i]>dep[x])?i:x;
		insert(fa[i],i);
	}
	mxdep=dep[x];
	while (cnt[x]==0&&x) d[++d[0]]=x,vis[x]=1,cnt[fa[x]]--,x=fa[x];
	for(tot=1;tot<=n-mxdep;tot++){
		for(int &i=ls[x];i;i=nx[i]) if (!vis[e[i]]){
			x=e[i],ans[tot]=d[d[0]];
			break;
		}
		while (cnt[x]==0&&x) d[++d[0]]=x,vis[x]=1,cnt[fa[x]]--,x=fa[x];
	}
	printf("0 ");
	while (d[0]) printf("%d ",d[d[0]--]);
	printf("\n%d\n",n-mxdep);
	for(i=n-mxdep;i>=1;i--) printf("%d ",ans[i]);
}

posted @ 2019-10-30 15:25  Deep_Thinking  阅读(89)  评论(0编辑  收藏  举报