左偏树
然后加了一些自己的理解
继续学习,加油呀 \(↖(^ω^)↗\)
#include<iostream>
using namespace std;
const int N=100010;
long long int fa[N]/*父结点*/,val[N]/*值*/,dis[N]/*当前结点距离外界点的距离*/,ls[N]/*左儿子*/,rs[N]/*右儿子*/;
bool vis[N];//标记是否用过
int find(int x)//找当前点x的根节点
{
if(fa[x]==x)//如果找到了就直接返回
{
return x;
}
else//否则继续递归寻找,然后进行一步路径压缩
{
return fa[x]=find(fa[x]);
}
}
int merge(int x,int y)//合并
{
if(!x||!y)//如果当前两个点有一个是空的(即有一个什么也没有)
{
return x+y;//直接返回他们两个相加的值
}
if(val[x]>val[y]/*如果x比y权值要大*/||(val[x]==val[y]/*x和y值相等*/&&x>y/*x的编号比y的编号要大*/))
swap(x,y);//交换,因为这棵树是左偏树,插入的话要从右边插入
//为了维护左偏树的性质,要把比较小的堆往比较大的堆里面插,所以如果第一个堆大的话,就交换一下,便于下面的操作进行
rs[x]=merge(rs[x],y);//递归合并右儿子与y,达到将y与右儿子合并的目的
fa[ls[x]]=fa[rs[x]]=fa[x]=x;//左儿子、右儿子、当前堆
if(dis[ls[x]]<dis[rs[x]]) swap(ls[x],rs[x]);//
dis[x]=dis[rs[x]]+1;
return x;
}
void Union(int x,int y)
{
int xx=find(x),yy=find(y);
if(vis[x]||vis[y]||xx==yy) return ;
fa[xx]=fa[yy]=merge(xx,yy);
}
void Delete(int x)
{
vis[x]=1;
fa[ls[x]]=ls[x];
fa[rs[x]]=rs[x];
fa[x]=merge(ls[x],rs[x]);
}
int get_ans(int x)
{
if(vis[x]) return -1;
int xx=find(x);
Delete(xx);
return val[xx];
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>val[i];
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1,opt,x,y;i<=m;i++)
{
cin>>opt>>x;
if(opt==1)
{
cin>>y;
Union(x,y);
}
else
{
cout<<get_ans(x)<<endl;
}
}
return 0;
}

浙公网安备 33010602011771号