配对堆模板

配对堆是一种可并堆

题意:两种操作,合并两个堆或者查询一个堆的最小值, n ≤ 1 0 6 n\leq 10^6 n106

P a i r i n g − H e a p Pairing-Heap PairingHeap还挺好写的,不过并没有传说中那么快
这里没有 D e c r e a s e − K e y Decrease-Key DecreaseKey的代码,说一下大概怎么实现
额外记录一个 F a t h e r Father Father域,执行 D e c r e a s e − K e y Decrease-Key DecreaseKey的时候,把该节点 x x x的子树抽出来(只是将 F a t h e r x Father_x Fatherx设为 0 0 0而不变动 F a t h e r x Father_x Fatherx的结构)
让后和根节点合并,当 P o p − M i n Pop-Min PopMin的时候,如果发现一个儿子的 F a t h e r Father Father不是自己那么就不把他加入合并的队列中,这样不影响时间复杂度
时间复杂度,除了 P o p − M i n Pop-Min PopMin都是 O ( 1 ) O(1) O(1)的, P o p − M i n Pop-Min PopMin应该是均摊 O ( log ⁡   n ) O(\log\ n) O(log n)
这玩意比左偏树还好写,也比左偏树快

#include
#define N 1000010
#define mid (l+r>>1)
using namespace std;
int n,m,b[N],c,f[N],d[N],rt[N];
struct tree{ int v,x,s,r; } s[N];
inline int gf(int x){
	for(;x^f[x];x=f[x]=f[f[x]]); return x;
}
inline int merge(int x,int y){
	if(s[x].v>s[y].v) x^=y^=x^=y;
	s[y].r=s[x].s; s[x].s=y; s[x].r=0; return x;
}
inline int cdq(int l,int r){
	if(l==r) return b[l];
	return merge(cdq(l,mid),cdq(mid+1,r));
}
inline int pop(int x){
	if(!s[x].s) return 0; c=0;
	for(int y=s[x].s;y;y=s[y].r) b[++c]=y;
	return cdq(1,c);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int x,i=1;i<=n;++i){
		scanf("%d",&x); s[i]=(tree){x,i,0,0}; rt[i]=f[i]=i;
	}
	for(int o,x,y;m--;){
		scanf("%d%d",&o,&x);
		if(o>1){
			if(d[x]){ puts("-1"); continue; }
			x=gf(x); printf("%d\n",s[rt[x]].v);
			d[s[rt[x]].x]=1; rt[x]=pop(rt[x]);
		} else {
			scanf("%d",&y);
			if(d[x] || d[y]) continue;
			x=gf(x); y=gf(y);
			if(x!=y){
				f[y]=x; rt[x]=merge(rt[x],rt[y]);
			}
		}
	}
}

你可能感兴趣的:(OI,数据结构,----优先队列,----并查集)