一、前置知识
- 外结点:左子树或右子树为空的结点
- 距离:左偏树种一个结点x到它子结点中最近外结点经过的边数,记为dist(x)(若外结点距离为0,空结点(null)的距离为-1)
二、概念
- 支持O(logn)合并的堆
三、性质
- 堆性质
- 左偏树中任意结点满足它的左子树的距离大于等于右子树的距离(左偏性质),即
- 左偏树中任意结点的左子树和右子树都是左偏树
四、定义
- 具有左偏性质的堆有序二叉树
#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 ;
}