左偏树

数据结构 左偏树

1.1 左偏树的功能

当我们需要数据结构支持“快速找出最大\最小值”时,很容易想到堆结构。这个优秀的数据结构可以\(O(\log n)\)地插入、删除数据。

但是,如果需要在此基础上,做到“快速合并”呢?这就需要用到一个比堆更高级的数据结构————左偏树。左偏树可以做到\(O(\log n)\)地维护堆结构的同时,\(O(\log n)\)地合并两个堆

2.1 左偏树的定义

外结点:左偏树是一棵二叉树,称子结点不满的结点为外结点

1VnhFO.md.png

距离:该结点到任意外结点的最近树上距离,边权均为1

左偏树上的任意结点满足:左儿子的距离\(\geq\) 右儿子的距离

2.2 左偏树的性质

性质一:若树的最大距离为\(d\),则结点数\(\geq 2^d\)

尝试采用归纳法证明:

当最大距离为\(0\)时,最小结点数为1,即该树只由一个点构成。这个应该很好理解(^-^)

最大距离为\(d-1\)时满足性质一,那么最大距离为\(d\)时:由定义可知,右儿子距离等于\(d-1\),左儿子距离大于等于\(d-1\),求和结果肯定大于等于\(2^d\)

1VuwnI.png

性质二:一棵结点数为\(n\)的左偏树,其最大距离\(\leq \log n\)

证完性质一后,性质二显然可以得证。性质二是一条是十分重要的性质,它保证了左偏树所有操作的时间复杂度。

3 操作

3.1 基本操作——merge

merge操作可以\(O(\log n)\)地合并两棵左偏树。

假设,树A的根结点权值大于树B的根结点权值(如果不是则交换)。那么,保留树A的根结点及其左子树结构,递归合并树A的右儿子和树B。

1VKXRg.md.png

由于性质二,树高不过\(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 删除

当我们需要删除一个左偏树的根时,只需要合并根的左、右儿子即可。

1VMWT0.png

3.3 增加

增加一个结点其实与合并一棵树别无二样,因此把新增结点当成一棵树,正常合并即可。

4 例题

4.1 Monkey King

模板题,审清题意后,套用左偏树即可

4.2 [APIO2012]派遣

维护最大值以求出“不超过\(m\)的最大忍者个数”,再来一个左偏树维护子树中的“最大领导力”

4.3 [JLOI2015]城池攻占

左偏树上打标记。每次将标记打在根结点上,合并时pushdown即可。

posted @ 2020-06-29 22:02  ticmis  阅读(216)  评论(0)    收藏  举报