zoukankan      html  css  js  c++  java
  • 【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;

     

     

  • 相关阅读:
    简单排序
    vue router在history模式下 如何部署在tomcat上
    概率论复习纲要
    MyBatis学习笔记(持续更新 2021/01/06- 2021/01/10)
    JavaWeb学习笔记(持续编辑2021/1/5-)
    2021/01/10周学习总结
    将WiFi搞得可以认证石铁大校园网(小米3路由器)
    对老师的建议
    自我感觉加分项
    github、gitee冲突配置ssh key
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/8690991.html
Copyright © 2011-2022 走看看