Codeforces963B - Destruction of a Tree

Portal

Description

给出一个\(n(n\leq2\times10^5)\)个点的树,每次可以删除一个度数为偶数的点及其相连的边,求一种能够删掉整棵树的方案。

Solution

简单起见,我们用“Odd树”和“Even树”表示大小为奇数/偶数的树。
首先易知原树为Even树时无解。因为每次都会删掉偶数条边而Even树有奇数条边。
当我们要删掉一棵树的时候,我们将其划分为三个部分:根,Odd子树,Even子树。对于一棵Odd树,其Odd子树必然有偶数个,那么我们可以按Even子树-根-Odd子树的删除顺序将原树变成若干个Odd树。因为删完Even子树后根剩下偶数个度数,可以删掉。
那么接下来要删掉根上有一个额外度数的Even树。一棵Even树的Odd子树必然有奇数个,那么我们依然可以按Even子树-根-Odd子树的删除顺序将原树变成若干个Odd树。因为删完Even子树后根剩下奇数个度数,加上一个额外度数就可以删掉。
...
容易知道上述过程是递归的。而由于子树的大小必然严格小于原树,所以递归会收敛到最小的Odd树(一个独立的点),最小的Even树(零个点),这两个都是可以直接删掉的。所以任意一个Odd树都可以按上述过程删掉。

时间复杂度\(O(n)\)

Code

//Destruction of a Tree
#include <bits/stdc++.h>
using std::vector;
inline char gc()
{
    static char now[1<<16],*s,*t;
    if(s==t) {t=(s=now)+fread(now,1,1<<16,stdin); if(s==t) return EOF;}
    return *s++;
}
inline int read()
{
    int x=0; char ch=gc();
    while(ch<'0'||'9'<ch) ch=gc();
    while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x;
}
const int N=2e5+10;
int n;
vector<int> to[N];
void edAdd(int u,int v) {if(u) to[u].push_back(v),to[v].push_back(u);}
int fa[N],siz[N];
void dfs(int u)
{
    siz[u]=1;
    for(int i=0;i<to[u].size();i++)
    {
        int v=to[u][i];
        if(v!=fa[u]) fa[v]=u,dfs(v),siz[u]+=siz[v];
    }
}
void del(int u)
{
    for(int i=0;i<to[u].size();i++)
    {
        int v=to[u][i];
        if(v!=fa[u]&&siz[v]%2==0) del(v);
    }
    printf("%d ",u);
    for(int i=0;i<to[u].size();i++)
    {
        int v=to[u][i];
        if(v!=fa[u]&&siz[v]%2==1) del(v);
    }
}
int main()
{
    n=read();
    if(n%2==0) {puts("NO"); return 0;}
    for(int i=1;i<=n;i++) edAdd(read(),i);
    dfs(1);
    puts("YES"),del(1);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/VisJiao/p/Cf963B.html