一、前置知识

  • 外结点:左子树或右子树为空的结点
  • 距离:左偏树种一个结点x到它子结点中最近外结点经过的边数,记为dist(x)(若外结点距离为0,空结点(null)的距离为-1)

二、概念

  • 支持O(logn)合并的堆

三、性质

  • 堆性质
  • 左偏树中任意结点满足它的左子树的距离大于等于右子树的距离(左偏性质),即dist(left(x))\geq dist(right(x))
  • 左偏树中任意结点的左子树和右子树都是左偏树

四、定义

  • 具有左偏性质的堆有序二叉树

例题:P3377 【模板】左偏树(可并堆)


#include<cstdio>
#include<iostream>
#include<algorithm>
#define MAXN 150010
#define ls a[x].son[0]
#define rs a[x].son[1]
using namespace std;
struct Tree{
    int dis,val,son[2],rt;
}a[MAXN];
inline int find(int x){
    return a[x].rt==x?x:a[x].rt=find(a[x].rt);
}
inline int merge(int x,int y){
    if(!x||!y)return x+y;
    if(a[x].val>a[y].val||(a[x].val==a[y].val&&x>y))swap(x,y);
    rs=merge(rs,y);if(a[ls].dis<a[rs].dis)swap(ls,rs);
    a[ls].rt=a[rs].rt=a[x].rt=x,a[x].dis=a[rs].dis+1;
    return x;
}
inline void del(int x){
    a[x].val=-1,a[ls].rt=ls,a[rs].rt=rs,a[x].rt=merge(ls,rs); 
}
int main(){
    int n,m;
    cin>>n>>m;a[0].dis=-1;
    for (int i=1;i<=n;++i)a[i].rt=i,scanf("%d",&a[i].val); 
    for (int i=1;i<=m;++i){
    	int opt,x;
        scanf("%d%d",&opt,&x);
        if(opt==1){
            int y;
            scanf("%d",&y);
            if (a[x].val==-1||a[y].val==-1)continue;
            int f1=find(x),f2=find(y);
            if(f1!=f2)a[f1].rt=a[f2].rt=merge(f1,f2);
        }else if(opt==2){
            if(a[x].val==-1)printf("-1\n");
            else printf("%d\n",a[find(x)].val),del(find(x));
        }
    }
    return 0 ;
}