您的位置:首页 > 其它

hdu1512 Monkey King【左偏堆、并查集】

2016-02-05 00:10 363 查看
今天临“放学”看了好久左偏堆未果,直到下载了一个课件==

我们定义节点i为外节点,当且仅当i的左子树或右子树为空。

  一个节点的距离为他到他后代中,最近的外节点所经过的边数。特别的,如果一个节点本身为外节点,则这个节点的距离为0。一棵子树的距离为这棵子树根节点的距离。为了方便,空节点的距离为-1。

  左偏树的左偏性质即左偏树的每个节点左子节点的距离都不小于右子节点的距离。

  即:dis(i,l)>=dis(i.r)

合并两个堆的伪代码

Function Merge(A,B)

  Begin

    If A=Null Then Return(B)

    If B=Null Then Return(A)

    If key(A)>key(B) then Swap(A,B)

    A.Right ← Merge(A.Right,B)

    If A.Right.dis>A.Left.dis Then

        Swap(A.Right,A.Left)

    If A.Right=Null Then A.dis ← 0

                    Else A.dis ← A.Right.dis+1

    Return(A)

  End

说明见下面的代码,然后还有一点就是,我们能看出来这是一个递归的函数,为什么做了递归呢?它的实现是把有着较小(因为要建大顶堆)的树作为另一颗树的一个分支插进去,那个树原来的分支作为新的树继续插进去,直到这个树折腾没,插入的过程结束了。然而还需要从下往上递归维护左偏堆的性质

代码不是我的,太困了==基本也是裸的题,没啥好写的

#include <iostream>
#include <vector>
using namespace std;

const int maxn = 100005;

struct tree {
int l, r, v, dis, f;
}heap[maxn];

int merge( int a, int b ) {
if( a == 0 ) return b;
if( b == 0 ) return a;
if( heap[a].v < heap[b].v ) swap( a, b );
heap[a].r = merge( heap[a].r, b );
heap[heap[a].r].f = a;
if( heap[heap[a].l].dis < heap[heap[a].r].dis ) swap( heap[a].l, heap[a].r );
if( heap[a].r == 0 ) heap[a].dis = 0;
else heap[a].dis = heap[heap[a].r].dis + 1;
return a;
}

int pop( int a ) {
int l = heap[a].l;
int r = heap[a].r;
heap[l].f = l;
heap[r].f = r;
heap[a].l = heap[a].r = heap[a].dis = 0;
return merge(l, r);
}

int find( int a ) { return heap[a].f == a ? a : find( heap[a].f ) ; }

void Read( int &x ) {
char ch;
x = 0;
ch = getchar();
while( !(ch >= '0' && ch <= '9') ) ch = getchar();
while( ch >= '0' && ch <= '9' ) {
x = x * 10 + ch - '0' ;
ch = getchar();
}
}

int main() {
// freopen( "c:/aaa.txt", "r", stdin );
int i, a, b, finda, findb, n, m;
while( scanf( "%d", &n ) == 1 ) {
for( i=1; i<=n; ++i ) {
Read(heap[i].v);
//scanf( "%d", &st[i].v );
heap[i].l = heap[i].r = heap[i].dis = 0;
heap[i].f = i;
}

//scanf( "%d", &m );
Read( m );
while( m-- ) {
//scanf( "%d %d", &a, &b );
Read( a ); Read( b );
finda = find( a );
findb = find( b );
if( finda == findb ) {
printf("-1\n");
} else {
heap[finda].v /= 2;
int u = pop( finda );
u = merge( u, finda );

heap[findb].v /= 2;
int v = pop( findb );
v = merge( v, findb );

printf( "%d\n", heap[merge( u, v )].v );
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: