【BZOJ 1078】 [SCOI2008]斜堆

1078: [SCOI2008]斜堆

Time Limit: 10 Sec  Memory Limit: 162 MB

Submit: 432  Solved: 250

[Submit][Status]

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

Mato的题解很详细。。

这道题的关键是一直在左边插入,于是就有的很多神奇的性质~

1.一个结点有右子树则必有左子树(右子树不可能单独存在)

2.最后插入的那个点一定是一直沿着左边往下走,并且没有右子树。

但是满足这个条件的点很多,分两种情况:

(一)x的左子树不是叶子:

如果左子树中还有满足这个条件的点y,最后插入的可能是y吗?

不可能!

如果y是最后插入的,那么必然经过了将x的左右子树交换这一过程,说明x原来只有右子树,与性质1:右子树不会单独存在矛盾。

因此得出结论,最后插入的一定是深度最小的那个满足条件的点。

(二)x的左子树是叶子:

和(一)一样来考虑,发现如果左子树是叶子,那么x和叶子作为最后一个插入点都是可行的。

为了满足字典序最小,我们选择叶子作为最后的插入点。

写个递归就ok了。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>
using namespace std;
int n,root,ans[105];
struct tree
{
	int l,r,fa;
}a[105];
void Get(int x,int now)
{
	if ((!a[x].r&&!a[x].l)||(!a[x].r&&a[x].l&&(a[a[x].l].l)))
	{
		a[a[x].fa].l=a[x].l;
		if (a[x].l)
			a[a[x].l].fa=a[x].fa;
		ans[now]=x;
		if (!a[x].fa) root=a[x].l;
		return;
	}
	Get(a[x].l,now);
	swap(a[x].l,a[x].r);
}
int main()
{
	root=1;
        scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		int x;
		scanf("%d",&x);
		x++;
		if (x<100)
		{
			a[x].l=i+1,a[i+1].fa=x;
		}
		else
		{
			x-=100;
			a[x].r=i+1,a[i+1].fa=x;
		}
	}
	a[1].fa=0;
	for (int i=n+1;i;i--)
		Get(root,i);
	for (int i=1;i<=n;i++)
		printf("%d ",ans[i]-1);
	cout<<ans[n+1]-1;
	return 0;
}

感悟:

1.WA是因为根是0的话会造成一些奇怪的问题,所以我把所有序号都加了1

2.首先根据奇怪的插入方式找到他的性质,然后逆向思维,从最后插入的点入手

时间: 2024-10-20 12:13:17

【BZOJ 1078】 [SCOI2008]斜堆的相关文章

[BZOJ]1078: [SCOI2008]斜堆

Time Limit: 10 Sec  Memory Limit: 162 MB Description 斜堆(skew heap)是一种常用的数据结构.它也是二叉树,且满足与二叉堆相同的堆性质:每个非根结点的值都比它父亲大.因此在整棵斜堆中,根的值最小.但斜堆不必是平衡的,每个结点的左右儿子的大小关系也没有任何规定.在本题中,斜堆中各个元素的值均不相同. 在斜堆H中插入新元素X的过程是递归进行的:当H为空或者X小于H的根结点时X变为新的树根,而原来的树根(如果有的话)变为X的左儿子.当X大于H

[BZOJ 1078][SCOI2008]斜堆(可并堆)

Description 斜堆(skew heap)是一种常用的数据结构.它也是二叉树,且满足与二叉堆相同的堆性质:每个非根结点的值 都比它父亲大.因此在整棵斜堆中,根的值最小.但斜堆不必是平衡的,每个结点的左右儿子的大小关系也没有任 何规定.在本题中,斜堆中各个元素的值均不相同. 在斜堆H中插入新元素X的过程是递归进行的:当H为空或者X 小于H的根结点时X变为新的树根,而原来的树根(如果有的话)变为X的左儿子.当X大于H的根结点时,H根结点的 两棵子树交换,而X(递归)插入到交换后的左子树中.

[bzoj1078][SCOI2008][斜堆] (贪心)

Description 斜堆(skew heap)是一种常用的数据结构.它也是二叉树,且满足与二叉堆相同的堆性质:每个非根结点的值都比它父亲大.因此在整棵斜堆中,根的值最小.但斜堆不必是平衡的,每个结点的左右儿子的大小关系也没有任何规定.在本题中,斜堆中各个元素的值均不相同. 在斜堆H中插入新元素X的过程是递归进行的:当H为空或者X小于H的根结点时X变为新的树根,而原来的树根(如果有的话)变为X的左儿子.当X大于H的根结点时,H根结点的两棵子树交换,而X(递归)插入到交换后的左子树中. 给出一棵

[SCOI2008]斜堆

题目大意 1.题目描述 斜堆(skew heap)是一种常用的数据结构. 它也是二叉树,且满足与二叉堆相同的堆性质: 每个非根结点的值都比它父亲大.因此在整棵斜堆中,根的值最小. . 但斜堆不必是平衡的,每个结点的左右儿子的大小关系也没有任何规定. 在本题中,斜堆中各个元素的值均不相同. . 在斜堆\(H\)中插入新元素\(X\) 的过程是递归进行的: (1)当\(H\)为空或者\(X\)小于\(H\)的根结点时, \(X\)变为新的树根,而原来的树根(如果有的话)变为\(X\)的左儿子. .

BZOJ1078: [SCOI2008]斜堆

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1078 每一次进入的点一定是一个极左节点,然后将它所处在的整棵树左右翻转.加上一些情况的处理. #include<cstring> #include<iostream> #include<algorithm> #include<cstdlib> #include<cstdio> #include<cmath> #include<

bzoj1078【SCOI2008】斜堆

1078: [SCOI2008]斜堆 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 662  Solved: 380 [Submit][Status][Discuss] Description 斜堆(skew heap)是一种常用的数据结构.它也是二叉树,且满足与二叉堆相同的堆性质:每个非根结点的值 都比它父亲大.因此在整棵斜堆中,根的值最小.但斜堆不必是平衡的,每个结点的左右儿子的大小关系也没有任 何规定.在本题中,斜堆中各个元素的值均不相同

斜堆,非旋转treap,替罪羊树

一.斜堆 斜堆是一种可以合并的堆 节点信息: struct Node { int v; Node *ch[2]; }; 主要利用merge函数 Node *merge(Node *x, Node *y) { if(!x) return y; if(!y) return x; if(x->v < y->v) swap(x, y); x->ch[1] = merge(x->ch[1], y); return swap(x->ch[0], x->ch[1]), x; }

堆之左式堆和斜堆

d-堆 类似于二叉堆,但是它有d个儿子,此时,d-堆比二叉堆要浅很多,因此插入操作更快了,但是相对的删除操作更耗时.因为,需要在d个儿子中找到最大的,但是很多算法中插入操作要远多于删除操作,因此,这种加速是现实的. 除了不能执行find去查找一般的元素外,两个堆的合并也很困难. 左式堆 左式堆可以有效的解决上面说的堆合并的问题.合并就涉及插入删除,很显然使用数组不合适,因此,左式堆使用指针来实现.左式堆和二叉堆的区别:左式堆是不平衡的.它两个重要属性:键值和零距离 零距离(英文名NPL,即Nul

[BZOJ1455]罗马游戏-斜堆/左偏树-并查集(+数据生成器)

Problem 遗产 题目大意 罗马皇帝很喜欢玩杀人游戏. 他的军队里面有n个人,每个人都是一个独立的团.最近举行了一次平面几何测试,每个人都得到了一个分数. 皇帝很喜欢平面几何,他对那些得分很低的人嗤之以鼻.他决定玩这样一个游戏. 它可以发两种命令: 1. Merger(i, j).把i所在的团和j所在的团合并成一个团.如果i, j有一个人是死人,那么就忽略该命令. 2. Kill(i).把i所在的团里面得分最低的人杀死.如果i这个人已经死了,这条命令就忽略. 皇帝希望他每发布一条kill命令