左偏树
左偏树是一种可以快速合并的可并堆,相对于普通的二叉堆,左偏树的合并可以做到log(p1+p2)log(p_1 + p_2)log(p1+p2),是一种十分优秀的数据结构。
性质
左偏树是一种可并堆的实现,是一颗二叉树,它除了有二叉树的左右儿子,还有2个属性,键和距离。下面是左偏树的一些基本性质。
- 节点的键值小于或等于左右子节点的键值。这是左偏树的堆性质。
- 节点的左子节点的距离不小于右子节点的距离。
- 节点的距离等于它的右子节点距离加一。
- 若左偏树的距离为一定值,则节点数最少的左偏树是完全二叉树。
- 若一棵左偏树的距离为kkk,则这棵左偏树至少有2k+1−12^{k + 1} -12k+1−1个节点。
- 一棵NNN个节点的左偏树距离最多为⌊log(N+1)−1⌋\lfloor log(N+1) -1 \rfloor⌊log(N+1)−1⌋。
操作
以下操作均维护一个小根堆,如果涉及到两个左偏树,那么树根分别为x,yx,yx,y,否则树根为xxx。
数据结构如下:
struct node {
int val, lc, rc, dis, fa;
}tree[nmax];
val表示值,lc合rc分别表示左子树合右子树,dis表示节点的距离,fa表示父亲(根据实际情况,有些题目不需要)。
合并
合并是最基本的操作,根据性质1,可以设计出以下算法。
- 简单情况,如果xxx为空树,直接返回yyy;如果yyy为空树,直接返回xxx。
- 如果不满足1,继续判断。如果xxx的根节点val大于yyy根节点的val,那么swap(xxx, yyy),目的是保证把大的合并到小的上。
- 将yyy的根和xxx的右子树判断是否满足2的规则,递归合并,缩小规模,直到一个叶子节点,那么直接修改tree[x].rc=ytree[x].rc = ytre