【luoguP4006 清华集训2017】小Y和二叉树

题目描述

小 Y 是一个心灵手巧的 OIer,她有许多二叉树模型。

小 Y 的二叉树模型中,每个结点都具有一个编号,小 Y 把她最喜欢的一个二叉树模型挂在了墙上,树根在最上面,左右子树分别在树根的左下方与右下方,且他们也都满足这样的悬挂规则。为了让这个模型更加美观,小 Y 选择了一种让这棵二叉树的中序遍历序列最小的悬挂方法。所谓中序遍历最小,就是指中序遍历的结点编号序列的字典序最小。

一天,这个模型不小心被掉在了地上,幸运的是,所有结点和边都没摔坏,但是她想不起这个模型原来是怎么悬挂的了,也就是说:她想不起来树根节点的编号了。

小 Y 最近忙于准备清华集训,所以没太多时间处理别的事情,她只好找到同样心灵手巧的你帮忙复原她的二叉树模型。

输入输出格式

输入格式:

 

从文件 binary.in 中读入数据。

第一行为一个正整数 n ,表示点的个数。

后接 n 行,每行若干个整数:

第 i + 1 行的第一个整数为 ki ,表示编号为 i 的结点的度数,后接 ki 个整数 ai; j ,表示编号为 i 的结点与编号为 ai; j 的结点之间有一条边。

同一行输入的相邻两个元素之间,用恰好一个空格隔开。

 

输出格式:

 

输出到文件 binary.out 中。

输出共一行, n 个整数,表示字典序最小的中序遍历。

题意:给一颗二叉树,你可以随意选择根节点和随意改变儿子顺序,求字典序最小的中序遍历;

题解:
①不断构造

②假定选好了根节点。mn[v]表示,v的子树中开头的最小值,(根除外)一个结点的度数小于等于2,一个节点可以开头。这样从根不断向下找mn小的做左儿子贪心可以构造出序列;

③现在找根节点,首先最左面的节点一定是固定的,为度数小于等于2的最小值;从这个点u不断往上找,预处理以u为根的所有mn[],然后u对有一个儿子的情况,那么mn较小的应该是u的右儿子,mn较大的应该是u的父亲,只有一个儿子v,mn[v]小于v,那么在真正的结构里v应该是u的右儿子,否则v是u的父亲;不断递归u向上找即可;

④最后再dfs一次输出答案;

 

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 const int N=1000010;
 5 int n,m,d[N],rt,st,o,hd[N],ls[N],rs[N],son[N][2],mn[N];
 6 struct Edge{int v,nt;}E[2*N];
 7 char gc(){
 8     static char *p1,*p2,s[10000000];
 9     if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
10     return(p1==p2)?EOF:*p1++;
11 }
12 int rd(){
13     int x=0; char c=gc();
14     while(c<'0'||c>'9') c=gc();
15     while(c>='0'&&c<='9') x=x*10+c-'0',c=gc();
16     return x;
17 }
18 void adde(int u,int v){E[o]=(Edge){v,hd[u]};hd[u]=o++;}//
19 void dfsA(int u,int fa){
20     int cnt=0;
21     for(int i=hd[u],v;i!=-1;i=E[i].nt){
22         if((v=E[i].v)==fa) continue;
23         son[u][cnt++]=v;
24         dfsA(v,u); 
25         mn[u] = min(mn[v],mn[u]);
26     }
27 }//
28 void find(int u){
29     if(d[u]==1&&u!=st) {rt=u;return;}
30     else if(u!=st&&d[u]==2||d[u]==1&&u==st){
31         if(son[u][0]<mn[son[u][0]]) find(son[u][0]);
32         else {rt=u; return;}
33     }
34     else{
35         if(mn[son[u][0]]>mn[son[u][1]]) find(son[u][0]);
36         else find(son[u][1]);
37     }
38 }//
39 int dfsB(int u,int fa){
40     if(d[u]==1&&u!=rt) return u;
41     int tmp=n+1; if(u!=rt&&d[u]==2||u==rt&&d[u]==1) tmp=u;
42     for(int i=hd[u],v,now;i!=-1;i=E[i].nt){
43         if((v=E[i].v)==fa) continue;
44         if((now=dfsB(v,u))<tmp) rs[u]=ls[u],ls[u]=v,tmp=now;
45         else rs[u]=v;
46     }
47     return tmp;
48 }//
49 void dfsC(int u){
50     if(ls[u]) dfsC(ls[u]);
51     printf("%d ",u);
52     if(rs[u]) dfsC(rs[u]);
53 }
54 int main()
55 {    freopen("mzoj1120.in","r",stdin);
56     freopen("mzoj1120.out","w",stdout);
57     n=rd();
58     for(int i=1;i<=n;i++){
59         hd[i]=-1;d[i]=rd();
60         for(int j=1;j<=d[i];j++) adde(i,rd());
61         if(d[i]<=2) {mn[i]=i; if(!st)st=i;} else mn[i]=n+1;
62     }
63     //d[st]++;
64     dfsA(st,0);
65     find(st);
66     dfsB(rt,0);
67     dfsC(rt);
68     return 0;
69 }//by tkys_Austin;

 

 

 

posted @ 2018-04-02 10:45  大米饼  阅读(515)  评论(0编辑  收藏  举报