• 【BZOJ 1078】 1078: [SCOI2008]斜堆


    1078: [SCOI2008]斜堆

    Description

      斜堆(skew heap)是一种常用的数据结构。它也是二叉树,且满足与二叉堆相同的堆性质:每个非根结点的值
    都比它父亲大。因此在整棵斜堆中,根的值最小。但斜堆不必是平衡的,每个结点的左右儿子的大小关系也没有任
    何规定。在本题中,斜堆中各个元素的值均不相同。 在斜堆H中插入新元素X的过程是递归进行的:当H为空或者X
    小于H的根结点时X变为新的树根,而原来的树根(如果有的话)变为X的左儿子。当X大于H的根结点时,H根结点的
    两棵子树交换,而X(递归)插入到交换后的左子树中。 给出一棵斜堆,包含值为0~n的结点各一次。求一个结点
    序列,使得该斜堆可以通过在空树中依次插入这些结点得到。如果答案不惟一,输出字典序最小的解。输入保证有
    解。

    Input

      第一行包含一个整数n。第二行包含n个整数d1, d2, ... , dn, di < 100表示i是di的左儿子,di>=100表示i
    是di-100的右儿子。显然0总是根,所以输入中不含d0。

    Output

      仅一行,包含n+1整数,即字典序最小的插入序列。

    Sample Input

    6
    100 0 101 102 1 2

    Sample Output

    0 1 2 3 4 5 6

    HINT

    Source

    【分析】

      这题要懂斜堆才能做。。

    考虑斜堆中最后插入的那个结点,容易发现:
    (1)它一定是一个极左结点(就是从根往它的路上一直都是沿着左链走),因为插入的时候每次都是插入到左子树中;
    (2)它一定木有右子树,因为插入的时候每次都是把原来的某棵子树作为新结点的左子树;

    满足(1)(2)的结点可能有多个,但紧接着可以发现,这个斜堆中的每个结点如果木有左子结点,那么也木有右子结点(或者说,每个非叶结点都有左子树),而在插入一个结点之前,其所有的祖先都被交换了左右子树,所以,若新结点的祖先中有满足(1)(2)的,且新结点不是叶结点,那么在新结点插入之前,这个满足(1)(2)的祖先必然是只有右子树而木有左子树的,这与上面的那个性质矛盾,所以,可以得出:最后插入的那个结点一定是满足(1)(2)的结点中,深度最小的那个(设为X),除非X的左子结点是叶结点,此时为了满足字典序最小,应该取X的左子结点为最后插入的。找到这个最后插入的结点以后,只需要把它删掉,并把它的所有祖先交换左右子树,就是插入该结点以前的状态了。这样可以找到字典序最小的插入顺序。

    ORZ大神:http://www.cppblog.com/MatoNo1/archive/2013/03/03/192131.html

    证明:斜堆中的每个结点如果木有左子结点,那么也木有右子结点:因为右儿子是由左儿子旋转得到的,而在旋转的同时左边一定被插入节点了。

      说得很清楚明白了,数据很小,直接暴力。

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<algorithm>
     6 using namespace std;
     7 #define Maxn 110
     8 
     9 int a[Maxn];
    10 
    11 struct node
    12 {
    13     int x,lc,rc,f;
    14 }t[2*Maxn];
    15 
    16 int op[Maxn],rt;
    17 
    18 int ffind()
    19 {
    20     int x=rt,nw;
    21     while(t[x].rc) x=t[x].lc;
    22     if(t[x].lc!=0&&t[t[x].lc].lc==0&&t[x].lc>x) nw=t[x].lc;
    23     else nw=x;
    24     
    25     if(nw==rt) rt=t[nw].lc,t[nw].f=0;
    26     else
    27     {
    28         t[t[nw].f].lc=t[nw].lc;
    29         t[t[nw].lc].f=t[nw].f;
    30         x=t[nw].f;
    31         while(1) 
    32         {
    33             swap(t[x].lc,t[x].rc);
    34             if(x==rt) break;
    35             x=t[x].f;
    36         }
    37     }
    38     return nw;
    39 }
    40 
    41 int main()
    42 {
    43     int n;
    44     scanf("%d",&n);
    45     op[0]=0;
    46     for(int i=0;i<n;i++) t[i].lc=t[i].rc=0;
    47     t[0].f=0;
    48     for(int i=1;i<=n;i++)
    49     {
    50         int x;
    51         scanf("%d",&x);
    52         if(x>=100) t[x-100].rc=i,t[i].f=x-100;
    53         else t[x].lc=i,t[i].f=x;
    54     }
    55     rt=0;
    56     for(int i=0;i<=n;i++)
    57     {
    58         op[i]=ffind();
    59     }
    60     for(int i=n;i>=0;i--) printf("%d ",op[i]);
    61     return 0;
    62 }
    View Code

    2017-01-17 15:00:26

  • 相关阅读:
    Dllimport函数時无法在Dll中找到的入口点
    cb35a_c++_STL_算法_for_each
    cb34a_c++_STL_算法_查找算法_(7)_lower_bound
    cb33a_c++_STL_算法_查找算法_(6)binary_search_includes
    cb32a_c++_STL_算法_查找算法_(5)adjacent_find
    cb31a_c++_STL_算法_查找算法_(4)find_first_of
    cb30a_c++_STL_算法_查找算法_(3)search_find_end
    cb29a_c++_STL_算法_查找算法_(2)search_n
    cb28a_c++_STL_算法_查找算法_(1)find_find_if
    cb27a_c++_STL_算法_最小值和最大值
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/6293101.html
Copyright © 2020-2023  润新知