【模板】左偏树(可并堆)

总的来说,可并堆仍然具有堆的性质,即:父节点和孩子节点之间的 key 值大小关系恒定。在此基础上,可并堆增加了可以快速合并的操作。

直观上来讲,因为一个二叉堆是采用完全二叉树的方式进行存储的,这是一个极其平衡的数据结构,但是也正是因为平衡,使得在合并的时候需要花很大力气来再次调整成平衡的结构。
而对于左偏树来说,这是一个左偏的数据结构,因此右边的距离相对较小,此时,每次都让一个堆的右子树和另一个堆进行合并,再调整,这样的时间复杂度就会相对二叉堆的调整低一些。

代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;

inline int read(){
	int x=0,f=1;char ch;
	do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
	do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
	return f*x;
}

struct node{//small-first
	#define lson h[x].lc
	#define rson h[x].rc
	int lc,rc;
	int key,dis,f;
}h[maxn];
int n,q;
bool del[maxn];

inline int find(int x){
	while(h[x].f)x=h[x].f;
	return x;
}

int merge(int x,int y){
	if(!x||!y)return x+y;
	if(h[x].key>h[y].key||(h[x].key==h[y].key&&x>y))swap(x,y);
	rson=merge(rson,y);
	h[rson].f=x;
	if(h[lson].dis<h[rson].dis)swap(lson,rson);
	h[x].dis=h[rson].dis+1;
	return x;
}

void erase(int x){
	del[x]=1;
	h[lson].f=h[rson].f=0;
	merge(lson,rson);
}

void read_and_parse(){
	n=read(),q=read();
	for(int i=1;i<=n;i++)h[i].key=read();
}

void solve(){
	while(q--){
		int opt=read();
		if(opt==1){
			int x=read(),y=read();
			if(!del[x]&&!del[y]){
				int fx=find(x),fy=find(y);
				if(fx^fy)merge(fx,fy);//与并查集一样,在合并的时候都是根节点进行合并
			}
		}else if(opt==2){
			int x=read();
			if(del[x])puts("-1");
			else{
				int fx=find(x);
				printf("%d
",h[fx].key);
				erase(fx);
			}
		}
	}
}

int main(){
	read_and_parse();
	solve();
	return 0;
}
原文地址:https://www.cnblogs.com/wzj-xhjbk/p/9877809.html