LibreOJ #2324.「清华集训 2017」小 Y 和二叉树 贪心

题意

有一棵二叉树,现在可以选定任意一个点为根,要求使得这棵二叉树的中序遍历字典序最小。
n 1000000

分析

不难发现若一个点度数小于3则一定可以成为第一个点。
那么我们可以先确定第一个点然后树形dp出以每个点为根编号最小且度数小于3的点。
然后从第一个点开始贪心,若走到某一棵子树内会使得答案更优,则走过去,不然就不走。
确定根后直接输出答案即可。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

const int N=1000005;

int n,cnt,last[N],deg[N],rt,mn[N];
struct edge{int to,next;}e[N*2];

int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

void addedge(int u,int v)
{
    e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;
}

void pre(int x,int fa)
{
    if (deg[x]<3&&x!=rt) mn[x]=x;
    else mn[x]=n;
    for (int i=last[x];i;i=e[i].next)
        if (e[i].to!=fa) pre(e[i].to,x),mn[x]=std::min(mn[x],mn[e[i].to]);
}

void dfs(int x,int fa)
{
    if (x!=rt&&deg[x]==1) {rt=x;return;}
    if (deg[x]<3) rt=x;
    int son1=0,son2=0;
    for (int i=last[x];i;i=e[i].next)
        if (e[i].to!=fa) son2=son1,son1=e[i].to;
    if (son2&&mn[son2]>mn[son1]) std::swap(son1,son2);
    if (deg[x]==3) dfs(son1,x);
    else if (deg[son1]==2&&son1<mn[son1]) dfs(son1,x);
    else if (deg[son1]==3)
    {
        int w=n;
        for (int i=last[son1];i;i=e[i].next)
            if (e[i].to!=x) w=std::min(w,mn[e[i].to]);
        if (son1<w) dfs(son1,x);
    }
}

void pri(int x,int fa)
{
    int son1=0,son2=0;
    for (int i=last[x];i;i=e[i].next)
        if (e[i].to!=fa) son2=son1,son1=e[i].to;
    if (son2&&mn[son2]<mn[son1]) std::swap(son1,son2);
    if (!son2&&mn[son1]>x) std::swap(son1,son2);
    if (son1) pri(son1,x);
    printf("%d ",x);
    if (son2) pri(son2,x);
}

int main()
{
    n=read();
    for (int i=1;i<=n;i++)
    {
        deg[i]=read();
        for (int j=1;j<=deg[i];j++)
        {
            int x=read();
            addedge(i,x);
        }
    }
    rt=n;
    for (int i=1;i<=n;i++) if (deg[i]<3) rt=std::min(rt,i);
    pre(rt,0);
    if (deg[rt]==1) dfs(rt,0);
    else
    {
        int son1=0,son2=0;
        for (int i=last[rt];i;i=e[i].next) son2=son1,son1=e[i].to;
        if (mn[son1]<mn[son2]) std::swap(son1,son2);
        dfs(son1,rt);
    }
    pre(rt,0);
    pri(rt,0);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_33229466/article/details/80752536