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;
}
posted @ 2019-09-27 20:22  Shiina_Mashiro  阅读(131)  评论(0编辑  收藏  举报