斜堆是一种可并堆。
我们需要维护可并堆森林,因此用并查集维护每个节点所属可并堆的根。
为了防止权值相同的情况,我们以编号作为偏序关系的第二关键字。
merge
merge实现合并两棵斜堆。
假如我们要合并的两个斜堆根是(u,v),不妨设(val_u<val_v)。
然后递归合并(u)的右儿子和(v),将递归合并后的根(u)的右儿子。
合并完之后需要交换(u)的左右儿子以保证复杂度,记得维护并查集。
然后交换最后维护一下并查集。
int merge(int x,int y)
{
if(!x||!y) return x|y;
if(val[x]>val[y]||(val[x]==val[y]&&x>y)) std::swap(x,y);
return rc=merge(rc,y),std::swap(lc,rc),fa[lc]=fa[rc]=fa[x]=x,x;
}
pop
pop实现弹出某个节点所在斜堆的根(x)。
直接把根的左右儿子合并起来就好了。
注意还要维护并查集,因为原斜堆中部分点在并查集中的的父亲为(x),所以要将(x)在并查集中的父亲设置为新的斜堆的根。
void pop(int x){val[x]=-1,fa[lc]=lc,fa[rc]=rc,fa[x]=merge(lc,rc);}