• Luogu P4006 小 Y 和二叉树


    题目
    我们知道,答案序列的第一个数一定是最小的度数不为(3)的点,记为(x)
    我们以(x)为根先(dfs)一遍,预处理出每个点的子树中最小的度数不为(3)的点的编号(f)
    我们知道(x)是答案的第一位,所以(x)一定在真正的二叉树的根的左下的最远处。
    所以我们再从(x)开始从左下往右上(dfs)
    假设我们当前(dfs)到的点是(u),我们分几种情况:
    1、(deg_u=1)
    搞笑吧.
    2、(deg_u=2)
    假设唯一的出点为(v)
    如果(f_v<v),那么最优的方案为把(v)接在(u)的右儿子上,(u)就是这棵树的实际的根。
    如果(f_v=v),搞笑吧。
    如果(f_v>v),那么最优的方案为让(v)(u)的父亲。
    3、(deg_u=3)
    设出点为(ls,rs(f_{ls}<f_{rs}))
    此时最优的方案显然是把(ls)接在(u)的右儿子上,让(ls)(u)的父亲。
    上面就是所有的情况。
    如果我们让(v)做了(u)的父亲,那么我们继续从(v)(dfs)
    如果我们让(v)做了(u)的右儿子,那么我们用另一个(dfs)来做以(v)为根的子树最小中序遍历。

    #include<bits/stdc++.h>
    #define pb push_back
    using namespace std;
    namespace IO
    {
        char ibuf[(1<<21)+1],obuf[(1<<21)+1],st[15],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21);
        char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
        void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
        void Put(char x){*oS++=x;if(oS==oT)Flush();}
        int read(){int x=0;char ch=Get();while(ch>57||ch<48)ch=Get();while(ch>=48&&ch<=57)x=x*10+(ch^48),ch=Get();return x;}
        void write(int x){int top=0;while(x)st[++top]=(x%10)+48,x/=10;while(top)Put(st[top--]);Put(' ');}
    }
    using namespace IO;
    void swap(int &a,int &b){a^=b^=a^=b;}
    const int N=1000007,inf=1e9;
    vector<int>E[N];
    int n,rt,cnt,deg[N],ans[N],f[N],id[N];
    void dfs(int u,int fa)
    {
        f[u]=(deg[u]^3? u:inf),id[u]=u;
        for(int v:E[u])  if(v^fa) dfs(v,u),f[v]<f[u]? f[u]=f[v],id[u]=v:0;
    }
    void dfs1(int u,int fa)
    {
        if(id[u]^u) dfs1(id[u],u);ans[++cnt]=u;
        for(int v:E[u]) if(v^id[u]&&v^fa) dfs1(v,u);
    }
    void dfs2(int u,int fa) 
    {
        ans[++cnt]=u;
        if(deg[u]==1) return;
        int ls=0,rs=0;
        for(int v:E[u])
        {
    	if(v==fa) continue;
    	if(deg[u]==2) return v<f[v]? dfs2(v,u):dfs1(v,u);
    	ls? rs=v:ls=v;
        }
        if(f[ls]>f[rs]) swap(ls,rs);
        dfs1(ls,u),dfs2(rs,u);
    }
    int main()
    {
        n=read();int i,j;
        for(i=1;i<=n;++i)
        {
    	for(deg[i]=read(),j=1;j<=deg[i];++j) E[i].pb(read());
    	if(deg[i]<3&&!rt) rt=i;
        }
        dfs(rt,0),++deg[rt],dfs2(rt,0);
        for(i=1;i<=n;++i) write(ans[i]);
        return Flush(),0;
    }
    
  • 相关阅读:
    Mint linux中调整屏幕亮度的方法
    poj 1085 Triangle War (状压+记忆化搜索)
    CF1060F Shrinking Tree
    leetcode492
    leetcode258
    leetcode226
    leetcode371
    leetcode104
    leetcode389
    leetcode448
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/11600172.html
Copyright © 2020-2023  润新知