左偏树

左偏树

啥是左偏树呢?

大概是这样的

这里需要注意两点:

  1. 左偏树是一棵二叉树,也是一种可并堆,拥有堆的性质,可以像堆一样合并。
  2. 左偏树顾名思义,有“左偏”的特点,既每个左子树节点的dist一定大于等于右子树节点的dist。

就比如像是什么\(priority \_ queue\)啥的既支持插入一个元素,还能查询最小/大元素,这直接STL就可以操作。但是要是某些毒瘤题目里让我们来使两个堆合并(其实算是正常操作吧),就不能用STL的\(priority\_queue\)来肝了【前提是不算\(pb\_ds\)那种神仙专属库】

有关左偏树的某些定义

距离

我们不妨设(能且仅能设)\(dist[i]\)表示一个节点它到离它最近的外节点的距离。

叶子节点的dist=0,空节点的dist=0

外节点

我们定义一个节点为外节点,当且仅当这个节点的左子树和右子树中的一个是空节点。(注意外节点不是叶子节点)

一些神奇的操作

合并

因为左偏树节点不满足完全二叉树而且十分左偏的性质,我们可以在一个log的复杂度中合并两个堆。

这个合并分为下面几步:

  1. 1:若是其中一个堆是空的,直接return 另一个堆
    2:否则选择一个堆顶val较大的堆作为父亲节点
    3:(如果是val相等那么使用堆顶dist相对比较大的堆作为父亲节点)
  2. 那么现在我们将根节点的右子树和另一个堆递归合并即可
  3. 如果左右儿子dist需要修正那么交换左右儿子
  4. 更新根节点dist
插入一个新的元素

一个新的元素就是一个只有一个节点的左偏树,直接合并这个左偏树和原先的左偏树即可。

弹出栈顶元素

我们可以合并根节点的左右子树,然后删除根节点

\(Code\)

#include <iostream>
#include <cstdio>
using namespace std;
inline int read() {
	int num = 0;
	char ch = getchar();
	bool flag = false;
	while (!isdigit(ch)) flag = ch == '-', ch = getchar();
	while (isdigit(ch)) num = (num << 1) + (num << 3) + (ch ^ 48), ch = getchar();
	return flag ? -num : num;
}
template<typename Tp>
struct Heap_node {
	int lson, rson;
	int dist;
	Tp val;
	Heap_node() {
		lson = rson = dist = 0;
	}
};
const int SIZE = 1000086;
struct Heap {
	Heap_node<int> tree[SIZE];
	int rt, cnt, tot;
	inline int New(int val) {
		++tot;
		tree[tot].val = val;
		return tot;
	}
	inline void set_dist(int n) {
		tree[n].dist = tree[n].rson ? (tree[tree[n].rson].dist + 1): 0;
	}
	int merge(int a, int b) {
		if (a == 0 || b == 0)
			return a + b;
		else if (tree[a].val > tree[b].val)
			swap(a, b);
		else if (tree[a].dist < tree[b].dist)
			swap(a, b);
		tree[a].rson = merge(tree[a].rson, b);
		if (tree[a].lson != 0 && tree[a].rson != 0) {
			if (tree[tree[a].lson].dist < tree[tree[a].rson].dist)
				swap(tree[a].lson, tree[a].rson);
		} else if (tree[a].lson == 0 && tree[a].rson != 0)
			swap(tree[a].lson, tree[a].rson);
		set_dist(a);
		return a;
	}
	inline void insert(int val) {
		cnt++;
		int b = New(val);
		rt = merge(rt, b);
	}
	inline void pop() {
		if (rt == 0)
			return;
		else {
			cnt--;
			int a = tree[rt].lson, b = tree[rt].rson;
			rt = merge(a, b);
		}
	}
	inline int top() {
		return rt ? tree[rt].val : 0;
	}
	inline size_t size() {
		return cnt;
	}
	Heap() {
		rt = tot = cnt = 0;
	}
} h;
int n = read();

int main() {
	while (n--) {
		int opt = read();
		switch (opt) {
			case 1:
				h.insert(read());
				break;
			case 2:
				printf("%d\n", h.top());
				break;
			case 3:
				h.pop();
				break;
			default:
				break;
		}
	}
	return 0;
}

posted @ 2019-10-27 16:59  卍GC卐  阅读(154)  评论(0编辑  收藏  举报