左偏树

来自学姐 Sunny_r 的博客数据结构

然后加了一些自己的理解

继续学习,加油呀 \(↖(^ω^)↗\)

#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;
}
posted @ 2021-08-15 16:50  晨曦时雨  阅读(66)  评论(0)    收藏  举报
-->