CF963B Solution

题目链接

题解

下文将有偶数个节点的树称之为“偶树”,而奇数个结点的树称之为“奇树”。

如果输入的树为偶树,一定无法全部摧毁,因为\(n-1\)为奇数而每次删去偶数条边。同样,在删点过程中,森林中的每棵树一定只能为奇树。因此如果要删去一棵树的根节点(设编号为1的点为根节点),必须保证这颗树的全部子树都为奇树。而对于偶子树,我们需要递归直至一个节点的子树全部为奇树时才可将其删去。总结一下,对于每一个根节点,需要依次执行3个操作:1. 递归删去所有偶子树;2.删去根节点;3.递归奇子树。

AC代码

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int fst[N],nxt[2*N],v[2*N],cnt;
int siz[N],ans[N],pos;//siz[i]:以编号为i的节点为根的子树大小
void add(int a,int b)
{
	v[++cnt]=b;
	nxt[cnt]=fst[a]; fst[a]=cnt;
}
void dfs1(int x)//计算子树大小
{
	siz[x]=1;
	for(int i=fst[x];i;i=nxt[i])
	{
		int y=v[i];
		if(siz[y]) continue;
		dfs1(y); siz[x]+=siz[y];
	}
}
void dfs2(int x,int fa)
{
    //递归删去偶子树
	for(int i=fst[x];i;i=nxt[i])
	{
		int y=v[i];
		if(y!=fa && siz[y]%2==0) dfs2(y,x);
	}
    //删去根节点
	ans[++pos]=x;
    //递归奇子树
	for(int i=fst[x];i;i=nxt[i])
	{
		int y=v[i];
		if(y!=fa && siz[y]%2) dfs2(y,x);
	}
}
int main()
{
	int n,p;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&p);
		if(p) {add(i,p); add(p,i);}
	}
	if(n%2==0) {printf("NO"); return 0;}
	dfs1(1); dfs2(1,0);
	printf("YES\n");
	for(int i=1;i<=pos;i++) printf("%d\n",ans[i]);
	return 0;
}
posted @ 2021-01-03 22:30  violet_holmes  阅读(60)  评论(0编辑  收藏  举报