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;
}