P3835
发现不用指针写的FHQ-Treap题解似乎被撤了,来一发吧
0.替罪羊树
单纯记录一下代码
1.FHQ-treap
不会写treap的左转P3369 【模板】普通平衡树,这里强烈推荐这篇题解。
FHQ Treap 的优点包括好理解,上手快,代码一般很短,可持久化等。
与一般Splay最大的不同就是它是无旋的。
啥意思呢?
就是说,通过拆树和合并代替Splay的旋转操作。
具体怎么实现呢?
1.1 插入
首先,把树分为左半树和右半树,然后暴力插
这里随便找个例子
3
/ \
2 6
/ /\
1 5 7
比如,我现在要把4插进去。
直接调用一下,嘿!4比3大,比6小,那不就得了
所以变成这样两棵树
3
/
2 6
/ /\
1 5 7
再把4塞到左树的右子节点上,送他一个右儿子6
3
/\
2 4
/ \
1 6
/\
5 7
懂了吧
其中找位置 \(O(logn)\),插入 \(O(1)\),总计 \(O(logn)\)
1.2 删除
同理可得,把插入的操作反过来就行
具体操作,就是把它删了,它的左子树并到它的父节点,再把右子树并到左子树上
还是这个树
3
/\
2 4
/ \
1 6
/\
5 7
现在我要把6删了
则先暴力删6
3
/\
2 4
/
1
5 7(注意这里是两棵树)
再分别把5,7接上去
3
/\
2 4
/ /
1 5
\
7
显然 \(O(1)\),是操作中最快的。
1.3 查询
一个一个说
通常来说,使用分裂和合并来实现更加简洁,但是速度会慢一点。
我喜欢快,所以代码会使用一般treap的查找方式。
1.3.1 查询 M 中有多少个数比 \(x\) 小,并且将得到的答案加一。
显然,找第一个小于 \(x\) 的树即可。
实现时可查询第一个不大于 \(x-1\) 的数,复杂度 \(O(logn)\)
1.3.2 查询如果将 M 从小到大排列后,排名位于第 \(x\) 位的数。
记录size,比它大就往左,比它小就往右
复杂度 \(O(logn)\)
1.3.3 查询 M 中 \(x\) 的前驱/后继
一起说。
前驱:找左子树的最右子节点
后继:找右子树的最左子节点
直接套1.3.2即可
1.4复杂度分析
空间复杂度,至多 \(n\) 个节点,故 \(O(n)\)
时间复杂度,每次查询至多 \(O(logn)\),整体共 \(O(nlogn)\),可以通过
2.可持久化FHQ-treap
与其他可持久化数据结构类似。
核心思想是:尽可能新建更少的结点记录新版本的信息,同时保留住历史版本的结点信息。
所以每更改一个结点就要分值一个新的结点出来,否则你修改的就是历史版本上的结点。
由于本题不强制在线,可直接套FHQ-treap。
3.代码
点击查看代码
4.结语
两年半的算法吟
by yzc001
两年半光阴飞逝去,
初窥门径亦懵懂。
屏幕代码夜星稀,
Bug 缠身心彷徨。
搜索剪枝如履冰,
动态规划似迷宫。
AC 喜悦胜琼浆,
WA 苦涩泪沾裳。
从数组到线段树,
从模拟到最短路。
算法思维渐清晰,
编程能力日臻健。
曾记赛场手心汗,
也曾深夜挑灯干。
失败教训铭于心,
成功喜悦更勇敢。
莫道信息路漫漫,
坚持不懈终登攀。
OIer们多努力,
NOI金牌等着你!

浙公网安备 33010602011771号