堆满足,比如说小根堆那就是一个点的值比它子树内所有点的都小


Leftist Tree

左偏树可以实现
O ( 1 ) O(1) O(1):查询最值 (find-max)
O ( log ⁡ n ) O(\log n) O(logn):删除最值(delete-max),修改排名为k的值(increase/decrease-key),插入(insert),合并(meld)

对于一棵二叉树,定义一个没有左儿子或者没有右儿子的节点为外节点
定义外节点 X 的 Dist[X] = 1,
非外节点 Y 的 Dist[Y] = min(Dist[LeftChild[Y]], Dist[RightChild[Y]]) + 1,
空节点 Z 的 Dist[Z] = 0
那么 Dist[ROOT] <= ceil[log(n+1)]

左偏树?
左偏树满足对任意非外节点 Y 有 Dist[LeftChild[Y]] > Dist[RightChild[Y]]

左偏树也叫做可并堆。递归合并。
对当前合并的子树 U 和 V,首先取值较小的那个根作为合并后的根,把它的其中一个儿子跟另一个堆合并。合并完如果不左偏了就把左右儿子交换。
假如你直接定义左儿子是 Dist 比较大的那个儿子,那就省去交换了。
因为直到某一个堆为空的时候就结束了,所以合并的复杂度是 O ( log ⁡ ∣ U ∣ + log ⁡ ∣ V ∣ ) O(\log |U|+\log|V|) O(logU+logV)

插入,只要合并就行了

删除堆顶,等价于合并根的左右儿子

删除指定一点,等价于把这点的左右儿子合并了,然后往上一路更新 Dist 同时维护左偏性质(交换 or 利用定义省去交换)

左偏树建起来比较有意思
放一个队列,每次取出两个队首合并然后放到队尾直到合并完成

左偏树可持久化。


Fibonacci Heap

斐波那契堆可以实现:
O ( 1 ) O(1) O(1):find-max, insert, meld
O ( 1 ) O(1) O(1)Amortized:increase/decrease-key
O ( log ⁡ n ) O(\log n) O(logn)Amortized:delete-max

斐波那契堆的几种操作复杂度是均摊的。
Strict Fibonacci 把那几个均摊变成了 worst-case。
详见 doi:10.1145/2213977.2214082


Pairing Heap

没学


Priority Queue

cppreference

除了 find-max O ( 1 ) O(1) O(1),其它的可以全部当成 O ( l o g n ) O(log n) O(logn)
注意某些堆是可以线性构造的。但是在优先队列里如果一个一个 Insert 的话,复杂度是 O ( n log ⁡ n ) O(n\log n) O(nlogn)
O ( n ) O(n) O(n) 构造用优先队列自带的 constructor 就行了
当然也有可能必须动态构造,那就逐个加入吧。


Example

POJ3784 Running Median

逐个加入并查询中位数。可以离线。
一种做法是 Kth Number,不过这里我们用堆。

考虑堆,维护 Kth Number
那可以维护两个堆,保证存在 K 使得堆1和堆2中任意元素x和y都满足 x<K, y>K
于是就可以维护一个小根堆和一个大根堆。每次根据新加进来的数和小根堆堆顶的大小关系。假如大,就插入小根堆;假如小,就插入大根堆。
每次想要查询的时候,可以把大根堆或者小根堆的堆顶塞进另一个堆里,直到大小根堆的 Size 满足要求。当然这个方法真的用来求 Kth 并不好,但是你可以发现假如只是要找中位数,这样每次新加入一个数,最多只会这么塞一次。
O ( log ⁡ n ) O(\log n) O(logn)

这题还可以用链表离线,也是比较有趣的做法。

注意输出格式。

#include<cstdio>
#include<cstdlib>
#include<cctype>
#include<iostream>
#include<cmath>
#include<queue>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define MAXN 16384
int P, N, M, Med;
int A[MAXN];
struct cmp
{
	bool operator () (const int &a, const int &b) const {
		return A[a] > A[b];
	}
};

priority_queue<int, vector<int>, cmp > HeapMin;
int HeapMax[MAXN];
int HMTOP;
int HeapMax_C[MAXN][2];
int HMSIZE[MAXN];
int HeapMax_Dist[MAXN];
#define LSON(x) HeapMax_C[x][HeapMax_Dist[HeapMax_C[x][0]] < HeapMax_Dist[HeapMax_C[x][1]]]
#define RSON(x) HeapMax_C[x][HeapMax_Dist[HeapMax_C[x][0]] > HeapMax_Dist[HeapMax_C[x][1]]]
int HMMERGE(int y, int x) {
	if (!x || !y) {
		return x + y;
	}
	int New_Y = A[y] > A[x] ? y : x;
	HMSIZE[New_Y] = HMSIZE[x] + HMSIZE[y];
	LSON(New_Y) = HMMERGE(LSON(New_Y), x + y - New_Y);
	HeapMax_Dist[New_Y] = HeapMax_Dist[RSON(New_Y)] + 1;
	return New_Y;
}
void HeapMax_Push(int x) {
	HeapMax_Dist[x] = 1;
	HMSIZE[x] = 1;
	HeapMax_C[x][0] = 0;
	HeapMax_C[x][1] = 0;
	HMTOP = HMMERGE(HMTOP, x);
}
void HeapMax_Pop() {
	if ((LSON(HMTOP) | RSON(HMTOP)) == 0) {
		HMTOP = 0;
		return;
	}
	HMTOP = HMMERGE(LSON(HMTOP), RSON(HMTOP));
}
void Insert(int X) {
	if (HeapMin.empty() || A[X] > A[HeapMin.top()]) {
		HeapMin.push(X);
	}
	else {
		HeapMax_Push(X);
	}
	if (HMSIZE[HMTOP] + 1 < (int)HeapMin.size()) {
		HeapMax_Push(HeapMin.top());
		HeapMin.pop();
	} else if (HMSIZE[HMTOP] - 1 > (int)HeapMin.size()) {
		HeapMin.push(HMTOP);
		HeapMax_Pop();
	}
}
int GetMedian() {
	if ((int)HeapMin.size() < HMSIZE[HMTOP])
		return A[HMTOP];
	else
		return A[HeapMin.top()];
}
int main() {
	cin >> P;
	while (P--) {
		while (!HeapMin.empty())
			HeapMin.pop();
		HMTOP = 0;
		cin >> N >> M;
		Med = (M + 1) >> 1;
		printf("%d %d\n", N, Med);
		for (int i = 1; i <= M; ++i) {
			cin >> A[i];
			Insert(i);
			if ((i & 1) == 0)
				continue;
			cout << GetMedian();
			if (((i+1)>>1)!=Med) {
				if(((i+1)>>1)%10==0)
					putchar('\n');
				else
					putchar(' ');
			}
		}
		if (P) cout << endl;
	}
	// system("pause");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值