1078: [SCOI2008]斜堆
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 803 Solved: 441
[ Submit][ Status][ Discuss]
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
100 0 101 102 1 2
Sample Output
HINT
Source
题解:可并堆
转载自:http://www.cppblog.com/MatoNo1/archive/2013/03/03/192131.html
考虑斜堆中最后插入的那个结点,容易发现:
(1)它一定是一个极左结点(就是从根往它的路上一直都是沿着左链走),因为插入的时候每次都是插入到左子树中;
(2)它一定木有右子树,因为插入的时候每次都是把原来的某棵子树作为新结点的左子树;
满足(1)(2)的结点可能有多个,但紧接着可以发现,这个斜堆中的每个结点如果木有左子结点,那么也木有右子结点(或者说,每个非叶结点都有左子树),而在插入一个结点之前,其所有的祖先都被交换了左右子树,所以,若新结点的祖先中有满足(1)(2)的,且新结点不是叶结点,那么在新结点插入之前,这个满足(1)(2)的祖先必然是只有右子树而木有左子树的,这与上面的那个性质矛盾,所以,可以得出:最后插入的那个结点一定是满足(1)(2)的结点中,深度最小的那个(设为X),除非X的左子结点是叶结点,此时为了满足字典序最小,应该取X的左子结点为最后插入的。找到这个最后插入的结点以后,只需要把它删掉,并把它的所有祖先交换左右子树,就是插入该结点以前的状态了。这样可以找到字典序最小的插入顺序。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define N 203
using namespace std;
int n,fa[N],lch[N],rch[N],size[N],mark[N],ans[N];
int root;
void find(int num)
{
int x=root;
while (rch[x]!=-1) x=lch[x];
if(lch[x]!=-1&&lch[lch[x]]==-1&&rch[lch[x]]==-1) x=lch[x];
ans[num]=x;
if (x==root) root=lch[x];
if (lch[x]!=-1) fa[lch[x]]=fa[x];
if (fa[x]!=-1) lch[fa[x]]=lch[x];
int t=fa[x];
fa[x]=lch[x]=rch[x]=-1;
while (t!=-1) swap(lch[t],rch[t]),t=fa[t];
}
int main()
{
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
memset(lch,-1,sizeof(lch));
memset(rch,-1,sizeof(rch));
memset(fa,-1,sizeof(fa));
scanf("%d",&n);
root=0;
for (int i=1;i<=n;i++) {
int x; scanf("%d",&x);
if (x>=100) x-=100,rch[x]=i,fa[i]=x;
else lch[x]=i,fa[i]=x;
}
for (int i=n;i>=0;i--)
find(i);
for (int i=0;i<n;i++) printf("%d ",ans[i]);
printf("%d",ans[n]);
}