数据结构学习笔记

可并堆(左偏树)

模板题:合并操作和删除根节点操作合并、删除和添加元素


左偏树有一个重要数组 \(dist\),不是很容易维护,但是方大佬指导可以用一个节点的子树大小表示 \(dist\),且可得证。


核心操作是 \(merge\) 即合并,先挑出需要合并的 \(x\)\(y\) 中值较小的一个,设为 \(x\),然后 \(x\) 为新根,\(x\) 的左节点为新根的左节点,\(x\) 的右节点与 \(y\) 进行递归合并,递归合并后的新树作为新根的右节点。注意当需要合并的两个树其中一个为空时,特判。


删除根节点就是合并根节点的左节点和右节点。


查询一个节点所在树的根节点,可以用并查集实现

  • 合并两个树时将两个树的原根的父亲都设为新根
  • 删除一个根时将这个根、这个根的左右儿子的父亲全部设为新根

更改元素时,最好直接删除原元素,再建一颗树,不要在原树上改,因为左偏树的跳根操作涉及到了并查集,并查集用路径压缩后很多点的父亲都是原元素,直接更改容易出错。


有的时候合并两个树的时候,会出现一个树是空树的情况,这时候由于要给两个树的 \(fa_i\) 赋值,就会出现给 \(fa_0\) 的错误,这时候要及时给 \(fa_0\) 赋值为 \(0\)

另外,出现这种情况的大部分情况是一个点对应了一个堆,而这个点对应的这个堆又有可能是个空堆。这种情况下,一般这个点有一个 \(belong_i\)\(p_i\),来对应自己的堆,因此就一定要及时更新这个值,以免这个值还是 \(0\)

参考题目:P3261 [JLOI2015] 城池攻占

线段树 进阶

线段树的 pushup 不仅可以在 \(O(1)\) 的时间内完成更新,也可以利用递归等手段以较高的复杂度完成较复杂的更新,以此解决更困难的问题。

参考题目:P4198 楼房重建

超级牛牛的线段树分治

模板题:(基于时间的)区间加边判断二分图

一般解决的问题是关于时间轴的,在某些时间有添加操作,在某些时间有删除操作,这时候发现添加容易删除难,于是就用线段树记录下来某一个东西在某段时间内是存在的,然后回答关于某一个时间的问题时,就从根节点往下找,遇到某个东西在这一段里面都存在时,就添加进去。


线段树的节点信息的区间有时是基于时间的,写代码时务必注意,防止出错。


由于线段树分治存在撤销操作,有些均摊复杂度的东西(比如并查集路径压缩)就要找东西平替了。

线段树二分

参考题目:P8955 「VUSC」Card Tricks

可以基于时间,或者操作数量等等可二分的内容,用于需要二分,但是 \(check\) 不允许 \(On\) 的复杂度,并且 \(check\) 来的值可以用线段树维护(比如参考题目中的前 \(mid\) 个操作的或值),就可以用线段树二分计算了。

可持久化数据结构

可持久化 Trie

模板题:区间最大异或和


要注意树里面存的是什么,比如前缀和、异或和,不能只简单地存数值。


一般查询都是区间 \(l\)\(r\) 之间查询,这时候可持久化 Trie 可以做到 \(1\)\(r\) 之间的答案,但是如果要满足 \(l\) 之后,可以给每个节点赋值一个它最后被改变(无论是添加还是被添加时遍历)的时间,如果这个时间 \(\ge l\),就可以,否则就不进入。

可持久化线段树

模板题:可持久化数组区间第 \(k\) 小(主席树)

posted @ 2024-01-20 16:17  cndark_moon  阅读(41)  评论(0)    收藏  举报