bzoj 1078: [SCOI2008]斜堆 (可并堆)

来源:互联网 发布:潍坊淘宝托管 编辑:程序博客网 时间:2024/05/17 23:41

1078: [SCOI2008]斜堆

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 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

6
100 0 101 102 1 2

Sample Output

0 1 2 3 4 5 6

HINT

Source

[Submit][Status][Discuss]


题解:可并堆

转载自: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 203using 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]);}



0 0
原创粉丝点击