QQ联系我

BZOJ 1078: [SCOI2008]斜堆

1078: [SCOI2008]斜堆

Time Limit: 10 Sec  Memory Limit: 162 MB

Submit: 1007  Solved: 555

[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

6
100 0 101 102 1 2

Sample Output

0 1 2 3 4 5 6

题解

题目中的斜堆有以下性质:

1.每个点若不是叶结点,一定有左儿子。

2.最后插入的点一定是一直向左放,并且最后插入的点没有右儿子。

3.若最左边的链上有多个没有右儿子的点,那么最后插入的点是深度最小的点,因为若最后插入的点是它下面的点,那么它的左右儿子一定交换过,因为他没有右儿子,所以它交换之前没有左儿子,不满足性质1。

4.若最左边的链上若深度最小的没有右儿子的点的左儿子是叶结点,那么这两个点都有可能的最后插入的,因为若深度大的点是最后插入的,那么深度小的那个点之前没有儿子,所以是满足性质1的。

因为题目要输出字典序最小的序列,所以遇到性质4的情况肯定选择深度大的点为最后插入的,每次将最后插入的点删除,再将路径上的点的左右儿子都交换。

代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=105;
int n,rt;
int l[N],r[N],fa[N],ans[N];
void dfs(int now,int u){
	if(!r[u]){
		if(l[u]&&!l[l[u]])dfs(now,l[u]);
		else{
			ans[now]=u;
			if(u==rt)rt=l[u];
			else{
				l[fa[u]]=l[u];
				fa[l[u]]=fa[u];
			}
		}
		return;
	}
	dfs(now,l[u]);
	swap(l[u],r[u]);
}
int main(){
	scanf("%d",&n);
	int x;
	for(int i=1;i<=n;i++){
		scanf("%d",&x);
		if(x<100)l[x]=i;
		else r[x-100]=i;
		fa[i]=x%100;
	}
	for(int i=n+1;i>=1;i--){
		dfs(i,rt);
	}
	for(int i=1;i<=n+1;i++){
		printf("%d ",ans[i]);
	}
	printf("\n");
	return 0;
}
posted @ 2017-10-31 21:26  czy020202  阅读(168)  评论(0编辑  收藏  举报