题意:n个节点的树,操作:删除度数为偶数的顶点以及他所有的边.
n<=1e5,问是否能通过操作把所有节点都删除,若能输出操作序列,否则输出NO.
每次删除偶数度的顶点,也就是每次删除某个点其偶数个边.
若顶点数为偶数,那么有奇数条边 永远会有一条边不会被删除,此时肯定无解.
若顶点数为奇数,那么至少有一个点的度为偶数 (因为总的度数为偶数),此时一定有解.
要想删叶子节点 就必须删掉其父节点.
顺着叶子往上找到第一个度数为偶数的点u,此时u的子树中所有的点的度都为奇数.
那么此时删除u.u的儿子度数都变为偶数.不断往下 可以删除整个子树u.
n<=1e5,问是否能通过操作把所有节点都删除,若能输出操作序列,否则输出NO.
每次删除偶数度的顶点,也就是每次删除某个点其偶数个边.
若顶点数为偶数,那么有奇数条边 永远会有一条边不会被删除,此时肯定无解.
若顶点数为奇数,那么至少有一个点的度为偶数 (因为总的度数为偶数),此时一定有解.
要想删叶子节点 就必须删掉其父节点.
顺着叶子往上找到第一个度数为偶数的点u,此时u的子树中所有的点的度都为奇数.
那么此时删除u.u的儿子度数都变为偶数.不断往下 可以删除整个子树u.
不断在u的上部分(偶数个边)找到深度最深得偶数度顶点.set维护偶数度的二元组(dep[u],u)即可.
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> ii;
const int N=2e5+5;
int n,u,v,rt,deg[N],dep[N];
bool vis[N];
vector<int> e[N];
void dfs(int u,int fa,int level)
{
dep[u]=level;
for(int i=0;i<e[u].size();i++)
if(e[u][i]!=fa)
dfs(e[u][i],u,level+1);
}
int main()
{
//ios::sync_with_stdio(false);
//cin.tie(0);
scanf("%d",&n);
for(int u=1;u<=n;u++)
{
scanf("%d",&v);
if(v==0)
rt=u;
else
{
e[v].push_back(u);
e[u].push_back(v);
deg[u]++,deg[v]++;
}
}
if(n%2==0)
{
puts("NO");
return 0;
}
puts("YES");
dfs(rt,0,0);
set<ii> s;
for(int i=1;i<=n;i++)
if(deg[i]%2==0)
s.emplace(ii(-dep[i],i));;
while(!s.empty())
{
ii t=*s.begin();
s.erase(s.begin());
int u=t.second;
printf("%d\n",u);
vis[u]=true;
for(int i=0;i<e[u].size();i++)
{
int v=e[u][i];
if(vis[v]) continue;
deg[v]--;
if(deg[v]%2==0)
s.emplace(ii(-dep[v],v));
else
s.erase(s.find(ii(-dep[v],v)));
}
}
return 0;
}
//7
//0 1 2 3 3 3 1