D. Destruction of a Tree
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output
You are given a tree (a graph with n vertices and n - 1 edges in which it's possible to reach any vertex from any other vertex using only its edges).
A vertex can be destroyed if this vertex has even degree. If you destroy a vertex, all edges connected to it are also deleted.
Destroy all vertices in the given tree or determine that it is impossible.
Input
The first line contains integer n (1 ≤ n ≤ 2·105) — number of vertices in a tree.
The second line contains n integers p1, p2, ..., pn (0 ≤ pi ≤ n). If pi ≠ 0 there is an edge between vertices i and pi. It is guaranteed that the given graph is a tree.
Output
If it's possible to destroy all vertices, print "YES" (without quotes), otherwise print "NO" (without quotes).
If it's possible to destroy all vertices, in the next n lines print the indices of the vertices in order you destroy them. If there are multiple correct answers, print any.
Examples
input
Copy
5 0 1 2 1 2
output
Copy
YES 1 2 3 5 4
input
Copy
4 0 1 2 3
output
Copy
NO
Note
In the first example at first you have to remove the vertex with index 1 (after that, the edges (1, 2) and (1, 4) are removed), then the vertex with index 2 (and edges (2, 3) and (2, 5) are removed). After that there are no edges in the tree, so you can remove remaining vertices in any order.
题意:给你一颗树,问你每次只删除 度为偶数 的结点,能不能将整棵树删除完?
题解:这道题需要用贪心的思维进行dfs,先处理子结点,在处理父亲节点,因为如果先处理父亲结点的话,会使子结点的度发生改变(从偶数变奇数,且不会再变化);先删除子结点,可以使父亲的结点变化(从偶数变成奇数),但其还有子节点的话,可以使度从奇数又变回偶数,所以先删除子结点是最优策略。
1>. 先dfs出从根到叶子的顺序,将其存入 stack 中(先处理子结点);
2>. 每次从栈中弹出元素,判断其度是否为偶数,if -> 是,可以将其删除,(note:如果弹出的元素的dfs序小于其dfs序是不进行处理的),这时,其子节点的度也发生了变化,继续dfs下去,判断其子结点是否能删除完。
#include<set>
#include<map>
#include<list>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<bitset>
#include<iomanip>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define eps (1e-8)
#define MAX 0x3f3f3f3f
#define u_max 1844674407370955161
#define l_max 9223372036854775807
#define i_max 2147483647
#define re register
#define pushup() tree[rt]=tree[rt<<1]+tree[rt<<1|1]
#define nth(k,n) nth_element(a,a+k,a+n); // 将 第K大的放在k位
#define ko() for(int i=2;i<=n;i++) s=(s+k)%i // 约瑟夫
#define ok() v.erase(unique(v.begin(),v.end()),v.end()) // 排序,离散化
#define Catalan C(2n,n)-C(2n,n-1) (1,2,5,14,42,132,429...) // 卡特兰数
using namespace std;
inline int read(){
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' & c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
typedef long long ll;
const double pi = atan(1.)*4.;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fLL;
const int M=63;
const int N=5e5+5;
int du[N],v[N],per[N]; // du --> 存度 v --> 打标机 per --> 记录其父亲结点
stack<int>ss; // 存 dfs 序
queue<int>qq; // 存最终的删除结果
vector<int>vect[N]; // 图
void dfs(int x,int fa){ // 得到 dfs 序列
per[x]=fa;
ss.push(x);
for(int i=0;i<vect[x].size();i++){
int u=vect[x][i];
if(u==fa) continue;
dfs(vect[x][i],x);
}
return ;
}
void dfs1(int x){ // 从 x 结点起,dfs向下,看他的子孙节点能否全部删除
v[x]=1;
qq.push(x);
for(int i=0;i<vect[x].size();i++){
int u=vect[x][i];
du[u]--; // 将 x 删除,其子结点的 度 将会减少1
if((du[u]&1)||v[u]||per[x]==u) continue;
dfs1(u);
}
return ;
}
int main(){
int n,x,rt;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&x);
if(x==0){
rt=i;
continue;
}
else{
vect[x].push_back(i);
vect[i].push_back(x);
du[x]++;
du[i]++;
}
}
if(n%2==0){
printf("NO\n");
return 0;
}
dfs(rt,0);
memset(v,0,sizeof(v));
while(!ss.empty()){ // 从底向上
int d=ss.top();
ss.pop();
if(du[d]%2==0)
dfs1(d);
}
if(qq.size()<n)
printf("NO\n");
else{
printf("YES\n");
while(!qq.empty()){
printf("%d\n",qq.front());
qq.pop();
}
}
return 0;
}