题目
我们知道,答案序列的第一个数一定是最小的度数不为(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;
}