题意: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