蒟蒻的ACM数据结构(五)-左式堆

一.序

强烈安利<数据结构与算法分析-c语言描述>这本书!!!
更好的讲解可阅读该书.或者看这位大佬的博客%%

二.用处

这个左式堆啊~直接当作可以合并的二叉堆来理解,这是再最好不过的了,其他和堆没啥区别.

三.基本概念

零路径长(null pathength)
Npl(X):
结点X到一个没有两个儿子的结点的最短路径的长度。
这里我们定义没有两个儿子的结点的Npl(x)=1;Npl(NULL) = 0。

左堆和堆一样,也具有结构性质和堆序性质。左堆的结构性质是指:对于堆中的每一个结点X,它的左儿子的零路径长要不小于其右儿子的零路径长。
堆序信息与堆的一样,即:最小的结点应该是根节点,鉴于我们希望子树也是堆,那么每个子树的根节点也应该是最小的
这一性质必然会导致左堆是一个极其不平衡的树。
书上原话

四.合并

每次合并都从右子树开始合并.这图我也看不大懂,大致理解就好了.反正代码写出来,感觉和图的方法没大关系
1

五.代码实现

(一).结构

typedef struct heap* nd;
struct heap {
	int d, npl;
	nd lson, rson;
}*root;

npl指距离,左右儿子lson,rson,d表示该节点值.

(二).合并

nd merge(nd p, nd ip)
{
	if (p == NULL)
		return ip;
	if (ip == NULL)
		return p;
	if (ip->d > p->d)		//堆,小根<,大根>
		swap(p, ip);
	if (p->lson == NULL)
		p->lson = ip;
	else {
		p->rson = merge(p->rson, ip);
		if (p->lson->npl < p->rson->npl)	//保证性质不变
			swap(p->lson, p->rson);
		p->npl = p->rson->npl + 1;	//合并后,根节点的npl距离取右儿子的距离+1
	}
	return p;
}

(三).插入

插入这个命令,可以理解为,一个单个数的堆,与大堆合并.
即把要插入的数当作一个堆,与要插入的堆合并即可.

nd insert(nd p, int x)
{
	nd ip = (nd)malloc(sizeof(struct heap));
	if (ip == NULL) {
		cout << "error insert" << endl;
		exit(65530);
	}
	ip->lson = ip->rson = NULL;
	ip->npl = 0, ip->d = x;
	return p = merge(p, ip);
}

(四).删除

删除堆首的值,可以理解为,将堆根节点的左右儿子分成两个堆,然后再合并成一个新的堆.

nd pop(nd p)
{
	if (p == NULL) {
		cout << "error pop" << endl;
		exit(65530);
	}
	nd lp = p->lson, rp = p->rson;
	free(p);
	return merge(lp, rp);
}

(五).样例代码

#ifndef NULL
#define NULL 0;
#endif
using namespace std;

typedef struct heap* nd;
struct heap {
	int d, npl;
	nd lson, rson;
}*root;
void close(nd p)
{
	if (p == NULL)
		return;
	close(p->lson),close(p->rson);
	delete(p);
}
nd merge(nd p, nd ip)
{
	if (p == NULL)
		return ip;
	if (ip == NULL)
		return p;
	if (ip->d > p->d)		//堆的小根<,大根>
		swap(p, ip);
	if (p->lson == NULL)
		p->lson = ip;
	else {
		p->rson = merge(p->rson, ip);
		if (p->lson->npl < p->rson->npl)
			swap(p->lson, p->rson);
		p->npl = p->rson->npl + 1;
	}
	return p;
}
nd pop(nd p)
{
	if (p == NULL) {
		cout << "error pop" << endl;
		exit(65530);
	}
	nd lp = p->lson, rp = p->rson;
	free(p);
	return merge(lp, rp);
}
nd insert(nd p, int x)
{
	nd ip = (nd)malloc(sizeof(struct heap));
	if (ip == NULL) {
		cout << "error insert" << endl;
		exit(65530);
	}
	ip->lson = ip->rson = NULL;
	ip->npl = 0, ip->d = x;
	return p = merge(p, ip);
}

例题

(hdu 1512) Monkey King

http://acm.hdu.edu.cn/showproblem.php?pid=1512

Problem Description

Once in a forest, there lived N aggressive monkeys. At the beginning, they each does things in its own way and none of them knows each other. But monkeys can’t avoid quarrelling, and it only happens between two monkeys who does not know each other. And when it happens, both the two monkeys will invite the strongest friend of them, and duel. Of course, after the duel, the two monkeys and all of there friends knows each other, and the quarrel above will no longer happens between these monkeys even if they have ever conflicted.
Assume that every money has a strongness value, which will be reduced to only half of the original after a duel(that is, 10 will be reduced to 5 and 5 will be reduced to 2).
And we also assume that every monkey knows himself. That is, when he is the strongest one in all of his friends, he himself will go to duel.

Input

There are several test cases, and each case consists of two parts.
First part: The first line contains an integer N(N<=100,000), which indicates the number of monkeys. And then N lines follows. There is one number on each line, indicating the strongness value of ith monkey(<=32768).
Second part: The first line contains an integer M(M<=100,000), which indicates there are M conflicts happened. And then M lines follows, each line of which contains two integers x and y, indicating that there is a conflict between the Xth monkey and Yth.

Output

For each of the conflict, output -1 if the two monkeys know each other, otherwise output the strongness value of the strongest monkey in all friends of them after the duel.
Sample Input
5
20
16
10
10
4
5
2 3
3 4
3 5
4 5
1 5
Sample Output
8
5
5
-1
10
Author
JIANG, Yanyan
Source
ZOJ 3rd Anniversary Contest
Recommend
linle

解析

一开始有n只孤独的猴子,然后他们要打m次架,每次打架呢,都会拉上自己朋友最牛叉的出来跟别人打,打完之后战斗力就会减半,每次打完架就会成为朋友(正所谓不打不相识o(∩_∩)o)。问每次打完架之后那俩猴子最牛叉的朋友战斗力还有多少,若朋友打架就输出-1.

并查集+可并堆
每次猴子和猴子打架做朋友,就并在一起.
每次要打架就查一下是不是在一起的朋友,不是就打架,是就输出-1.

在经历了无数次re和mle后,我把close函数删了==,遗留的指针遗留就遗留吧.就ac了…wtf
在这里插入图片描述

#include <iostream>
#include <algorithm>
#include<cstring>
#include <cstdio>
#ifndef NULL
#define NULL 0;
#endif
using namespace std;

typedef struct heap* nd;
struct heap {
	int d, npl;
	nd lson, rson;
}*root;
struct vec {
	int d,fa;
	nd p;
	vec() {
		d = 0, p = NULL;
	}
}a[101000];
void close(nd p)
{
	if (p == NULL)
		return;
	close(p->lson);
	close(p->rson);
	delete(p);
}
nd merge(nd p, nd ip)
{
	if (p == NULL)
		return ip;
	if (ip == NULL)
		return p;
	if (ip->d > p->d)		//堆的小根<,大根>
		swap(p, ip);
	if (p->lson == NULL)
		p->lson = ip;
	else {
		p->rson = merge(p->rson, ip);
		if (p->lson->npl < p->rson->npl)
			swap(p->lson, p->rson);
		p->npl = p->rson->npl + 1;
	}
	return p;
}
nd pop(nd p)
{
	if (p == NULL) {
		cout << "error pop" << endl;
		exit(65530);
	}
	nd lp = p->lson, rp = p->rson;
	free(p);
	return merge(lp, rp);
}
nd insert(nd p, int x)
{
	nd ip = (nd)malloc(sizeof(struct heap));
	if (ip == NULL) {
		cout << "error insert" << endl;
		exit(65530);
	}
	ip->lson = ip->rson = NULL;
	ip->npl = 0, ip->d = x;
	return p = merge(p, ip);
}
int top(nd p)
{
	return p->d;
}
int ffa(int x)
{
	if (x == a[x].fa)
		return x;
	return a[x].fa=ffa(a[x].fa);
}
int read()
{
	int x = 0, f = 1; char c = getchar();
	while (c<'0' || c>'9') {
		if (c == '-')
			f = -1;
		c = getchar();
	}
	while (c >= '0'&&c <= '9') {
		x = x * 10 + c - '0';
		c = getchar();
	}
	return x * f;
}
int main()
{
	int n, m;
	while (~scanf("%d",&n)) {
		for (int i = 1; i <= n; i++) {
			a[i].d=read();
			a[i].fa = i;
			a[i].p = insert(a[i].p, a[i].d);
		}
		m=read();
		for (int i = 1; i <= m; i++) {
			int x, y, fx, fy;
			x=read(),y=read();
			fx = ffa(x), fy = ffa(y);
			if (fx != fy) {
				a[fy].fa = fx;
				int num1 = top(a[fx].p) / 2, num2 = top(a[fy].p) / 2;
				a[fx].p = pop(a[fx].p);
				a[fy].p = pop(a[fy].p);
				a[fx].p = a[fy].p = merge(a[fx].p, a[fy].p);
				a[fx].p = a[fy].p = insert(a[fx].p, num1);
				a[fx].p = a[fy].p = insert(a[fx].p, num2);
				cout << top(a[fx].p) << endl;
			}
			else
				cout << -1 << endl;
		}
		for (int i = 1; i <= n; i++) 
			a[i].p = NULL;
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
软件名称: 题海泛舟 软件版本: 1.0 软件作者: ccamp 作者邮件: ilovebd@263.net 软件网站: http://ccampsoft.yeah.net 下载地址: http://www.freewebz.com/ccamp/tihai.exe http://tj.skycn.net/down/tihai.exe 软件容量: 5.84M 软件语言: 简体文 授权形式: 共享 应用平台: WIN98/NT/ME/2000 发布日期: 2002年3月5日 软件介绍: 软件简介: 随着信息化社会的发展,越来越多的教师和教育工作者开始使用计算机来辅助教学。用计算机来出考试试卷就是其重要的一项。然而,输入题目的烦琐,查找题目的困难,这些使得使用计算机出卷变的费时费力,甚至还不如手写来得快速。 题海泛舟正是一个旨在解决上述问题的试题库软件。它集成了试题编辑、题库管理、抽取试卷等功能,非常适合与教师个人或学校使用。它可以使出卷变的真正轻松快捷。 功能特点: 支持多用户,使得不同题库间的管理变的简单容易,尤其适合在学校使用。 软件界面清新典雅,并可以更换界面,使您在工作时保持良好心情。 多种方式的录入题目方式,与WORD紧密结合,具有拖入窗口和强大的批量录入题目功能,使得录入题目高效轻松。 强大的查询功能,可以根据各种属性查询题目。 一目了然的树型目录显示题目,同时具有题目列表,并支持分类显示题目,使的管理查看题目轻而易举。 具有题目收藏功能,快速访问收藏题目。 快速插入符号公式上下标,并具有特色的插入自定义文字功能,可以简单输入如“Na2CO3";;;这样的复杂文字。 手动抽取题目只需拖动,并可以直接拖动类别。 随机抽取题目功能强大,支持难度分布组卷。 形成试卷选项多样,并具有试卷模版,可以直接保存为WORD文件。 备份,压缩,合并题库高效快速。 批量抽取试卷,一次抽取N份
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值