题外话:为啥这个小和Y中间有个空格,每次在前缀查询的网站都搜不出来
首先,一个度数=3的点不可能成为叶子节点
最左边的叶子节点就是这棵树的中序遍历的第一位,所以我们可以DP确定这个叶子节点是多少,设f[i]表示i点的子树中中序遍历的第一位最小可能是多少
然后确定了最终中序遍历的第一位之后,可以通过这个点向上扩展
具体的,如果这个点只有一个子树,判断一下这个点和子树的f的大小选择放在这个点右儿子还是父亲
如果有两个子树,那就f小的放右儿子,f大的放父亲,也要与根节点比较一下,讨论一下即可
Code:
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=1000010;
int n,m,d[N],rt,st;
int ls[N],rs[N];
int lc[N],rc[N],f[N];
int vis[N<<1],head[N<<1],nxt[N<<1],tot=0;
void add(int x,int y){vis[++tot]=y;nxt[tot]=head[x];head[x]=tot;}
void dfs1(int v,int fa){
for(int i=head[v];i;i=nxt[i]){
int y=vis[i];
if(y==fa) continue;
if(!lc[v]) lc[v]=y;else rc[v]=y;
dfs1(y,v);
f[v]=min(f[y],f[v]);
}
}
void find(int v){
if(d[v]==1 && v!=st) {rt=v;return;}
else if(v!=st && d[v]==2 || d[v]==1 && v==st){
if(lc[v]<f[lc[v]]) find(lc[v]);
else{rt=v;return;}
}
else{
if(f[lc[v]]>f[rc[v]]) find(lc[v]);
else find(rc[v]);
}
}
int dfs2(int v,int fa){
if(d[v]==1 && v!=rt) return v;
int tmp=n+1; if(v!=rt && d[v]==2 || v==rt && d[v]==1) tmp=v;
for(int i=head[v],now;i;i=nxt[i]){
int y=vis[i];
if(y==fa) continue;
if((now=dfs2(y,v))<tmp) rs[v]=ls[v],ls[v]=y,tmp=now;
else rs[v]=y;
}
return tmp;
}
void put(int v){
if(ls[v]) put(ls[v]);
cout<<v<<" ";
if(rs[v]) put(rs[v]);
}
int main(){
int size=100<<20;
__asm__ ("movq %0,%%rsp\n"::"r"((char*)malloc(size)+size));
n=read();
for(int i=1;i<=n;i++){
d[i]=read();
for(int x,j=1;j<=d[i];j++) x=read(),add(i,x);
if(d[i]<=2) {f[i]=i; if(!st) st=i;} else f[i]=n+1;
}
dfs1(st,0);find(st);dfs2(rt,0);
put(rt);
exit(0);
return 0;
}