这个人很勤快,什么都留下了。|

TuSalcc

园龄:3年2个月粉丝:4关注:2

左偏树/可并堆

概述

左偏树就是支持实现堆的合并的数据结构。它同时满足“左偏”和“堆”的性质。

我们定义 \(dis[u] = min(dis[lson[u]], dis[rson[u]])+1\) ,其中空节点 dis 为 0。

那么:

  • 左偏:对于任意节点 u,满足 \(dis[rson[u]] \leq dis[lson[u]]\),那么显然 \(dis[u] = dis[rson[u]] + 1\)
  • 堆:\(\forall u, val[u] \leq val[lson[u]], val[u] \leq val[rson[u]\)(小根堆),大根堆同理。

实现

为什么左偏树合并是\(log\) \(n\) 的呢?以小根堆为例:在我们合并两个堆的时候,显然是值较小的那一个堆的堆顶元素会作为新堆的堆顶元素。那么我们就把较小的作为堆顶,然后把另一个堆跟堆顶的右儿子进行合并。合并的过程是递归的,可以证明时间复杂度是 \(O(log\) \(n)\)

代码片段:

    if(!p || !q) return p + q;
	if(val[p] > val[q] || (val[p] == val[q] && p > q)) Swap(p, q);
	rson[p] = Merge(rson[p], q);
	if(dis[lson[p]] < dis[rson[p]]) Swap(lson[p], rson[p]);
	dis[p] = dis[rson[p]] + 1;
	return p;

删除堆顶元素只需合并根节点的左右两个儿子即可。

合并后每个元素在哪个堆可以用并查集实现。要路径压缩。

全部代码(Luogu P3377):

#include <cstdio>
#define Maxn 100000
using namespace std;
int n, m, root[Maxn + 9], tot, dis[Maxn + 9], lson[Maxn + 9], rson[Maxn + 9], val[Maxn + 9];
bool killed[Maxn + 9];
int read() {
	int x = 0, f = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
	return x * f;
}
int Find(int x) {return root[x] == x ? root[x] : root[x] = Find(root[x]);}
void Swap(int &x, int &y) {int t = x; x = y, y = t;}
int Merge(int p, int q) {
	if(!p || !q) return p + q;
	if(val[p] > val[q] || (val[p] == val[q] && p > q)) Swap(p, q);
	rson[p] = Merge(rson[p], q);
	if(dis[lson[p]] < dis[rson[p]]) Swap(lson[p], rson[p]);
	dis[p] = dis[rson[p]] + 1;
	return p;
}
int main() {
	n = read(), m = read();
	for(int i = 1; i <= n; ++ i) val[i] = read(), root[i] = i, dis[i] = 1;
	while(m --) {
		int opt = read();
		if(opt == 1) {
			int x = read(), y = read();
			if(killed[x] || killed[y]) continue;
			int rtx = Find(x), rty = Find(y);
			if(rtx == rty) continue;
			root[rtx] = root[rty] = Merge(root[rtx], root[rty]);
		}
		else {
			int x = read();
			if(killed[x]) {puts("-1"); continue;}
			int rtx = Find(x);
			printf("%d\n", val[rtx]);
			killed[rtx] = 1;
			root[rtx] = root[lson[rtx]] = root[rson[rtx]] = Merge(lson[rtx], rson[rtx]);
		}
	}
	return 0;
}

End

本文作者:TuSalcc

本文链接:https://www.cnblogs.com/TS357051/p/17783592.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   TuSalcc  阅读(6)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起