左偏树
左偏树
左偏树是一种可以让我们在
为了方便以下的左偏树为小根堆来讨论。
定义#
外结点:左儿子或者右儿子是空节点的结点。
距离:一个结点
性质#
-
左偏树具有堆性质,即若满足小根堆的性质,则对于每一个结点
,都有 。其中 为权值, 为左儿子,右儿子。 -
左偏树具有左偏的性质,即对于每一个点
,都有 。
基本结论#
结点
距离为
操作#
合并#
左偏树的很多操作都是需要用到合并操作的。
我们用 merge(x,y)
来表示合并两棵以
首先如果要是不考虑左偏的性质,假设我们合并的是小根堆:
-
若
,以 作为合并后的根节点;否则以 作为合并后的根节点。为了避免讨论,若有 我们就swap
一下。 -
将
与 的其中一个儿子合并,用合并后的根节点代替与 合并的儿子的位置,并返回 。 -
重复以上操作,如果
有一个是 ,就返回 ,也就是返回不为 的结点的编号。
当然上述的方法在数据为一条链的时候会 T 飞,所以我们需要让他左右保持一个相对平衡的状态,这个时候我们就有了左偏树(当然平衡树也可以)。
由于我们前面说过左偏树中左儿子的距离大于右儿子的距离,我们每次将
但是,两棵左偏树按照上述方法合并后,可能不再保持左偏树的左偏性质。在每次合并完之后,判断对结点
插入给定值#
我们可以直接新建一个点,然后将他和左偏树合并就好。
求最小(大)值#
由于满足堆的性质,所以我们直接返回堆顶的元素就好。
删除最小(大)值#
也就是删除堆顶元素,直接合并根节点的左右儿子即可。
删除任意结点#
inline void del(int x)
{
int tmp=merge(ls[x],rs[x]),fu=fa[x];
f[tmp]=fa[tmp]=fu;
f[x]=fa[x]=tmp;
ls[fu]==u?ls[fu]=tmp:rs[fu]=tmp;
while(fu)
{
if(dis[ls[fu]]<dis[rs[fu]])swap(ls[fu],rs[fu]);
if(dis[fu]==dis[rs[fu]]+1)return ;
dis[fu]=dis[rs[fu]]+1;
fu=fa[fu];
}
}
这里
我们和删除根节点一样先合并子树,然后存起来删除的点的父节点
然后合并后的点的父节点和所属点先设为
然后判断删除的点是父节点的左儿子还是右儿子然后用合并后的替换。
然后我们从父节点不断向上更新 swap
来维护左偏性质即可。
求给定结点所在的左偏树的根节点#
我们可以开个数组
我们思考一下,我们可以像并查集一样采用路径压缩的办法来让这个复杂度变低。
在合并两个结点的时候,令 f[x]=f[y]=merge(x,y)
。
在删除左偏树中的最值时,我们令 f[ls[x]]=f[rs[x]]=f[x]=merge(x,y)
,因为
code:
#include<bits/stdc++.h>
#define int long long
#define N 1000100
using namespace std;
int n,m,ls[N],rs[N],dis[N],f[N],vis[N];
struct sb{int id,w;bool operator<(sb x)const{return w==x.w?id<x.id:w<x.w;}}e[N];
inline int fid(int x){if(x==f[x])return x;return f[x]=fid(f[x]);}
inline int merge(int x,int y)
{
if(!x||!y)return x+y;
if(e[y]<e[x])swap(x,y);
rs[x]=merge(rs[x],y);
if(dis[ls[x]]<dis[rs[x]])swap(ls[x],rs[x]);
dis[x]=dis[rs[x]]+1;
return x;
}
signed main()
{
dis[0]=-1;
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>e[i].w,f[i]=i,e[i].id=i;
for(int i=1;i<=m;i++)
{
int op,x,y;
cin>>op;
if(op==1)
{
cin>>x>>y;
if(vis[x]||vis[y])continue;
int xx=fid(x),yy=fid(y);
if(xx==yy)continue;
f[xx]=f[yy]=merge(xx,yy);
}
else
{
cin>>x;
if(vis[x]){puts("-1");continue;}
int xx=fid(x);
cout<<e[xx].w<<endl;
vis[xx]=1;
f[ls[xx]]=f[rs[xx]]=f[xx]=merge(ls[xx],rs[xx]);
ls[xx]=rs[xx]=dis[xx]=0;
}
}
return 0;
}
作者: 北烛青澜
出处:https://www.cnblogs.com/Multitree/p/17472692.html
本站使用「CC BY 4.0」创作共享协议,转载请在文章明显位置注明作者及出处。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战