【SCOI2008】斜堆

【SCOI2008】斜堆

【题目描述】

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

【输入】

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

【输出】

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

【输入样例】

6
100 0 101 102 1 2

【输出样例】

0 1 2 3 4 5 6

【题解】

根据题意,首先要生成给定的斜堆。由于需要输出字典序最小的序列,而斜堆的根节点一定小于子树的每个节点,因此能越早插入根节点,得到的序列越优。
那么,可以插入根节点的条件是什么?不难发现,当斜堆中某一子树的根节点插入后,它将永远成为该子树的根节点,此后要将其它节点插入斜堆,根据斜堆的性质,只能是左右子树交替插入,所以只有平衡二叉树能够最先插入根节点。
如果子树不是平衡二叉树,那就让它成为“平衡二叉树”,再插入根节点,即哪一边子树节点数多,就先插入相应数目的节点,使得两边子树剩余未插入节点数绝对值之差小于1。
综上所述,对于每一个根节点,需要考虑的情况只有三种:
1)左右子树节点数相同(或左子树节点数比右子树节点数大1);
2)左子树节点数远大于右子树节点数(先插入左子树节点至两边子树节点数相同);
3)右子树节点数大于左子树节点数(先插入右子树节点至左子树节点数比右子树节点数大1)。
※括号里的内容可手工推导一下~
分类讨论的情况解决了,接下来该讨论插入的节点从哪里来了。对于每一个节点,都使用一个数组来记载以它为根,最优的插入序列,当然叶节点的序列中只有它自身。然后一个递归操作,按上面的规律合并每个节点的左右子树序列得到该节点的序列,那么根节点的序列自然就是需要的字典序最小的插入序列了。
※特别注意,斜堆可能是一条链或近似链,在储存时要预先算好范围(本蒟蒻在这里RE了无数次QAQ)。

【代码】

代码巨丑,本蒟蒻有一个点过不了所以特判了QAQ
长是长了点,不过应该很容易看懂吧TAT

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值