左偏树

左偏树是一种数据结构,板子都是蓝色的那种……

左偏树不像平衡树,它不是平衡的,甚至一条链也可能是左偏树。

左偏树可以用来维护堆,并且支持合并操作。

(以小根堆为例)

对于合并操作,我们取出两个左偏树较小的根作为合并后的左偏树的根,然后将此树的右子树和另一棵树合并,递归处理。

对于删除根,我们直接将其两颗子树合并即可。

洛谷模板

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

int read()
{
	int a = 0,x = 1;
	char ch = getchar();
	while(ch > '9' || ch < '0') {
		if(ch == '-') x = -1;
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9') {
		a = a*10 + ch-'0';
		ch = getchar();
	}
	return a*x;
}
const int N=1e6+7;
int n,m,ins[N];
struct node {
	int fa,dist,rs,ls;
	int val,id;
	#define fa(x) arr[x].fa
	#define dist(x) arr[x].dist
	#define rs(x) arr[x].rs
	#define ls(x) arr[x].ls
	#define val(x) arr[x].val
	#define id(x) arr[x].id
	friend bool operator < (node a,node b) {return (a.val!=b.val)?a.val<b.val:a.id<b.id;}
	friend bool operator > (node a,node b) { return !(a<b);}
}arr[N];

int find(int s)
{
	//printf("%d ",s);
	if(fa(s) == s) return s;
	else return fa(s) = find(fa(s));
}

int merge(int a,int b)
{
	if(!a || !b) return a|b;
	if(arr[a] > arr[b]) swap(a,b);
	fa(rs(a) = merge(rs(a),b)) = a;
	if(dist(ls(a)) < dist(rs(a))) swap(ls(a),rs(a));
	dist(a) = dist(rs(a)) + 1;
	return a;
}

void print(int x)
{
	if(x >= 10) print(x/10);
	putchar('0'+x%10);
}

void del(int x)
{
	print(val(x));putchar('\n');
	fa(x) = merge(ls(x),rs(x));
	fa(fa(x)) = fa(x);
	ins[x] = 0;
}

int main()
{
	
	n = read(),m = read();
	for(int i = 1;i <= n;i ++) {
		arr[i].val = read(),ins[i] = 1,id(i) = i;
		fa(i) = i;
	}
	for(int i = 1;i <= m;i ++) {
		int op = read();
		if(op == 1) {
			int x = read(),y = read();
			if(!ins[x] || !ins[y]) continue;
			if(find(x) == find(y)) continue;
			merge(find(x),find(y));
		} else {
			int x = read();
			if(ins[x]) {
				del(find(x));
			} else puts("-1");
		}
	}
	return 0;
}
posted @ 2020-09-30 19:19  nao-nao  阅读(184)  评论(0编辑  收藏  举报