[SCOI2008]斜堆

题目大意

1.题目描述

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

2.样例文件:

input1:
6
100 0 2 102 4 104
output1:
4 6 5 2 0 1 3
..............................................................
input2:
7
0 100 1 102 2 3 5
output2:
2 5 0 3 4 6 7 1

思路及解法:

本题的数据范围出到\(n \leq 5 \times 10^3\)是肯定没问题的。
所以总结一下,本题时间复杂度\(O(n^2)\),空间复杂度\(O(n)\),思维复杂度\(O(n!)\)....
.
言归正传,这题到底怎么做?
由于每次都是插入左子树中,所以就会有一些神奇的事情。
我们考虑 最后一个插入的点 会有什么性质:
(1)性质1:它是一个极左节点(从根到它的路径都是走左子树)
(2)性质2:它一定没有右子树
显然满足上述条件的点有很多,那么仔细观察后可以发现:
性质3:对于树上任意一个点,如果它没有左子树,则它一定没有右子树
.
然后就可以搞一波事情了。
我们假设最后加入的点为 \(X\) ,如果它的祖先中存在点 \(Y\) 也满足性质\(1,2\),则:
<1>
若\(X\)不为叶子节点:
由于\(X\)插入\(Y\)的子树中时会反转\(Y\)的左右儿子,
那么\(Y\)的当前左子树中包含\(X\),而现在\(Y\)又没有右子树,
所以在插入前,\(Y\)只有右子树,没有左子树。
这显然与性质3矛盾,即这种情况不可能发生。
所以最后插入的点一定是 深度最浅的满足性质1,2的节点,设它为 \(del1\)。
<2>
若\(X\)为叶子节点:
那么即插入\(X\)前\(Y\)没有儿子。
所以这种情况显然是合法的,
即如果\(del1\)有左儿子\(del2\),且\(del2\)为叶子节点,那么\(del2\)也是合法的。
.
综上所述,最后插入的点可能为:
(1)深度最浅的满足性质1,2的节点
(2)深度最浅的满足性质1,2的节点的左儿子,前提是这个左儿子为叶子节点。
由于我们要保证字典序,所以存在(2)情况时我们则优先选叶子节点。
所以我们依照这个原则不断删点、修改。
最后把答案数组倒着输出即可(P.s :建议把所有点的编号都加\(1\)再处理)。

实现代码:

#include<bits/stdc++.h>
#define RG register
#define IL inline
#define mx 60
#define ll long long
using namespace std;

int n,root,fa[60],ls[60],rs[60],ans[60];

IL void Work(){
    for(RG int sq = 1; sq <= n; sq ++){
        RG int del1 = 0 , del2 = 0, x = root;
        while(x){ if(!rs[x]){del1 = x; break;} x = ls[x]; }
        if(!rs[ls[x]] && !ls[ls[x]] && ls[x])
            del2 = ls[x];
        if(del2){ans[sq] = del2; ls[del1] = 0; }
        else {
            ans[sq] = del1;
            ls[fa[del1]] = ls[del1]; fa[ls[del1]] = fa[del1];
        }
        if(!del2 && del1 == root)root = ls[del1] , fa[root] = 0;;
        RG int ff = fa[(del2)?del2 : del1];
        while(ff)
            swap(ls[ff],rs[ff]) , ff = fa[ff];
    }return;
}

int main(){
    cin >> n; n++; root = 1;
    for(RG int i = 2,f; i <= n; i ++){
        cin >> f;
        if(f >= 100){f-=100; f++; rs[f] = i; fa[i] = f;}
        else f++ , ls[f] = i , fa[i] = f;
    }
    Work();
    for(RG int i = n; i >= 1; i --)ans[i] --;
    for(RG int i = n; i >= 1; i --)cout<<ans[i]<<" ";
    return 0;
}

原文地址:https://www.cnblogs.com/GuessYCB/p/8325072.html

时间: 2024-10-11 18:14:13

[SCOI2008]斜堆的相关文章

【BZOJ 1078】 [SCOI2008]斜堆

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

[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(递归)插入到交换后的左子树中. 给出一棵

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命令