Tinkoff Internship Warmup Round 2018 and Codeforces Round #475 (Div. 1) 963B 964D B Destruction of a Tree

  OvO http://codeforces.com/contest/963/problem/B

  CF 963B 964D

  对于题目要求,显然一开始的树,要求度数为偶数的节点个数为奇数个,通过奇偶讨论显然这个树总节点个数为奇数个

  然后对于每一步分割出来的树林,显然树林中每个树都得满足度数为偶数的节点个数为奇数个,同样地,可以得到树林中每个树的总结点为奇数个

  其实上面写的一些是废话,后文并不会用到……

  首先排除度数为偶数的节点有偶数个的树,即已至要讨论的树均满足度数为偶数的节点有奇数个

  从叶子节点往上搜(采用回溯),搜到第一个度数为偶数的节点 X,那么以 X 为根的子树中,必然只有这个根节点 X 的度数为偶数

  那么由于整棵树度数为偶数的节点有奇数个,所以去掉以 为根的子树后(X的父节点度数会发生改变),剩下的节点中,度数为偶数的节点仍然为奇数个

  对于以 X 为根的子树,因为除了根节点 X 以外其他节点度数均为奇数,所以可以通过一个简单的 DFS 直接清除整棵以 X 为根节点的子树

  去掉 X 后继续往上回溯,找到下一个度数为偶数的节点,过程同上。

#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <vector>
#include <set>

using namespace std;

const int M=2e5+44;

vector<int> vec[M];
int du[M],tag[M];
int n;
queue<int> que;
int ans[M],lans;

void dfs(int rt,int fa)
{
	int v,now,tmp;
	for(int i=0;i<vec[rt].size();i++)
		if(vec[rt][i]!=fa)
			dfs(vec[rt][i],rt);
	if((du[rt]&1)==0)
	{
		que.push(rt); du[fa]--;
		while(!que.empty())
		{
			now=que.front(); que.pop();
			ans[++lans]=now; tag[now]=1;
			for(int i=0;i<vec[now].size();i++)
			{
				v=vec[now][i]; if(v==fa) continue; if(tag[v]) continue;
				du[v]--; que.push(v);
			}
		}
	}
}

int main()
{
	int tmp;
	memset(du,0,sizeof(du));
	scanf("%d",&n);
	if((n&1)==0)
		return puts("NO"),0;
	for(int i=1;i<=n;i++)
		vec[i].clear();
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&tmp); if(tmp==0) continue;
		du[i]++; du[tmp]++;
		vec[i].push_back(tmp); vec[tmp].push_back(i);
	}
	while(!que.empty()) que.pop();
	dfs(1,-1);
	if(lans!=n) return puts("??"),0;
	puts("YES");
	for(int i=1;i<=lans;i++)
		printf("%d\n",ans[i]);
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/FxxL/p/8882051.html

相关文章