左偏树,顾名思义,就是向左倾斜的树
这棵破树就是用来实现可并堆的,也就是说,是比堆多出了一个合并的操作
左偏树的定义是:左边的节点个数大于右边的节点个数
这就使其可以资瓷合并的操作
比二叉堆的O(size1 + size2)快多了 这是O(logsize1 + size2)
三个性质(代码中要维护的三个性质)【还是从1开始吧】
- 当前节点的键值小于等于或大于等于它的左右儿子的键值(堆性质)
- 当前节点的左儿子的深度不小于右儿子的深度
- 当前节点的深度等于右儿子的深度+1
这篇由非常菜的选手写的博客只介绍merge和pop操作
struct hazaking
{
int son[2];//左右儿子指针
int fa;//父亲指针
int h;//深度
}tr[500005];
//以下为合并操作
//getfather懒得放
int merge(int x, int y)(这里的x y是两棵左偏树的根节点)
{
if (!x || !y) return x + y;//特判
if (vis[x] > vis[y] || ( ! (vis[x] ^ vis[y]) && x > y) ) swap(x, y); //维护堆性质
tr[x].son[1] = merge(tr[x].son[1], y);
tr[tr[x].son[1] ].fa = x;
if (tr[tr[x].son[0] ].h < tr[tr[x].son[1] ].h ) swap(tr[x].son[0], tr[x].son[1] );//维护左儿子深度不小于右儿子深度
tr[x].h = tr[tr[x].son[1] ].h + 1;//维护当前节点深度等于右儿子深度 + 1
return x;
}
//以下为删除操作
void del(int x)
{
vis[x] = -1;//标记
tr[tr[x].son[0] ].fa = tr[tr[x].son[1] ].fa = 0;//使根节点的两个儿子的父亲指针指向0
merge(tr[x].son[0], tr[x].son[1] );//合并被删除根的两棵子树
}