左偏树
a_sad_soul · · 个人记录
左偏树是一种支持在
Define
外结点 : 左儿子或者右儿子是空结点的结点。
距离:一个节点
左偏树的基本性质
左偏树具有堆的性质,还有左偏性质:即对于每个结点x,有
基本结论
1.结点
2.距离为
操作
合并
定义 merge(x,y) 为合并两棵分别以
这里以小根堆举例,大根堆则将判断大小的符号换过来即可。
-
若将
v_x\le v_y ,以x 作为合并之后的根节点, 否则以y 作为合并之后的根节点,若有v_x>v_y 交换x,y 。 -
将
y 与x 的其中一个儿子合并,用合并后的根节点代替与y 合并的儿子的位置,并返回x 。 -
重复操作,直到有一个为空。
-
返回时若有
dist_{ls}\ge dist_{rs} ,没有则交换两边,并且维护该数组为dist_x=dist_{rs}+1 。
int merge(int x,int y){
if(!x||!y)return x+y;
if(v[y]<v[x])swap(x,y);
rs(x)=merge(rs(x),y);
if(dist[ls(x)]<dist[rs(x)])swap(ls(x),rs(x));
dist[x]=dist[rs(x)]+1;
return x;
}
插入给定值
新建结点,并且合并即可。
求最值
最值为根节点的值(堆的性质)。
删除
将删除结点的左右结点合并,然后修改删除结点信息杰克。
最后再开一个维护父亲结点的数组维护父亲暴力跳即可。
这里维护父亲结点,可能会退化成
int find(int x){
if(rt[x]!=x)rt[x]=find(rt[x]);
return rt[x];
}
那么维护 rt[x] 可以塞进其它函数里面直接处理:
合并写法:
void Merge(int x,int y){
rt[x]=rt[y]=merge(x,y);
}
删除写法:
void Delete(int x){
rt[ls(x)]=rt[rs(x)]=rt[x]=merge(ls(x),rs(x));
}//rt也要改不然有些数字可能会指向rt[x]最后找不到正确根