CF 964D Destruction Of A Tree 思维,set

题意:n个节点的树,操作:删除度数为偶数的顶点以及他所有的边.
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


猜你喜欢

转载自blog.csdn.net/noone0/article/details/79996848