左偏树
数据结构 左偏树
1.1 左偏树的功能
当我们需要数据结构支持“快速找出最大\最小值”时,很容易想到堆结构。这个优秀的数据结构可以\(O(\log n)\)地插入、删除数据。
但是,如果需要在此基础上,做到“快速合并”呢?这就需要用到一个比堆更高级的数据结构————左偏树。左偏树可以做到\(O(\log n)\)地维护堆结构的同时,\(O(\log n)\)地合并两个堆
2.1 左偏树的定义
外结点:左偏树是一棵二叉树,称子结点不满的结点为外结点
距离:该结点到任意外结点的最近树上距离,边权均为1
左偏树上的任意结点满足:左儿子的距离\(\geq\) 右儿子的距离
2.2 左偏树的性质
性质一:若树的最大距离为\(d\),则结点数\(\geq 2^d\)
尝试采用归纳法证明:
当最大距离为\(0\)时,最小结点数为1,即该树只由一个点构成。这个应该很好理解(^-^)
最大距离为\(d-1\)时满足性质一,那么最大距离为\(d\)时:由定义可知,右儿子距离等于\(d-1\),左儿子距离大于等于\(d-1\),求和结果肯定大于等于\(2^d\)

性质二:一棵结点数为\(n\)的左偏树,其最大距离\(\leq \log n\)
证完性质一后,性质二显然可以得证。性质二是一条是十分重要的性质,它保证了左偏树所有操作的时间复杂度。
3 操作
3.1 基本操作——merge
merge操作可以\(O(\log n)\)地合并两棵左偏树。
假设,树A的根结点权值大于树B的根结点权值(如果不是则交换)。那么,保留树A的根结点及其左子树结构,递归合并树A的右儿子和树B。
由于性质二,树高不过\(O(\log n)\),因此递归的复杂度得以保证。
inline int merge(int a,int b){
if(!a||!b) return a|b;
if(val[a].fi>val[b].fi) swap(a,b);
ch[a][1]=merge(ch[a][1],b);
if(dis[ch[a][0]]<dis[ch[a][1]]) swap(ch[a][0],ch[a][1]);
dis[a]=dis[ch[a][1]]+1;
return a;
}
3.2 删除
当我们需要删除一个左偏树的根时,只需要合并根的左、右儿子即可。

3.3 增加
增加一个结点其实与合并一棵树别无二样,因此把新增结点当成一棵树,正常合并即可。
4 例题
4.1 Monkey King
模板题,审清题意后,套用左偏树即可
4.2 [APIO2012]派遣
维护最大值以求出“不超过\(m\)的最大忍者个数”,再来一个左偏树维护子树中的“最大领导力”
4.3 [JLOI2015]城池攻占
左偏树上打标记。每次将标记打在根结点上,合并时pushdown即可。



浙公网安备 33010602011771号