Destruction of a Tree CodeForces - 964D

题面

题意

给出一棵树,你可以摧毁其中度数为偶数的点,同时与之相连的点将被一起摧毁,问能否摧毁所有点,若能,还要输出方案.

做法

首先可以发现点数为偶数的肯定不行,因为每次删除偶数条边,因此对于一对父子,若子节点的字子树大小为奇数,则肯定先摧毁其父节点再摧毁它,反之先摧毁其父节点再摧毁它,我们可以据此得出父子间的先后关系,再进行拓扑排序即可得出答案.

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#define N 200100
using namespace std;

int n,bb,first[N],size[N],ds[N],ans[N],aa;
struct Bn
{
    int to,next;
}bn[N<<1];
vector<int>vec[N];
queue<int>que;

inline void add(int u,int v)
{
    bb++;
    bn[bb].to=v;
    bn[bb].next=first[u];
    first[u]=bb;
}

void gs(int now,int last)
{
    int p,q;
    size[now]=1;
    for(p=first[now];p!=-1;p=bn[p].next)
    {
        if(bn[p].to==last) continue;
        gs(bn[p].to,now);
        size[now]+=size[bn[p].to];
    }
}

void dfs(int now,int last)
{
    int p;
    for(p=first[now];p!=-1;p=bn[p].next)
    {
        if(bn[p].to==last) continue;
        if(size[bn[p].to]%2)
        {
            vec[now].push_back(bn[p].to);
            ds[bn[p].to]++;
        }
        else
        {
            vec[bn[p].to].push_back(now);
            ds[now]++;
        }
        dfs(bn[p].to,now);
    }
}

int main()
{
    memset(first,-1,sizeof(first));
    int i,j,p,q;
    cin>>n;
    for(i=1;i<=n;i++)
    {
        scanf("%d",&p);
        if(p) add(p,i),add(i,p);
    }
    if(n%2==0)
    {
        puts("NO");
        return 0;
    }
    puts("YES");
    gs(1,-1);
    dfs(1,-1);
    for(i=1;i<=n;i++)
    {
        if(!ds[i]) que.push(i);
    }
    for(;!que.empty();)
    {
        p=que.front();
        que.pop();
        printf("%d\n",p);
        for(i=0;i<vec[p].size();i++)
        {
            ds[vec[p][i]]--;
            if(!ds[vec[p][i]])
            {
                que.push(vec[p][i]);
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/yzyyylx/article/details/79988929