平衡树注意事项
FHQ Treap
- 按值分裂时,不要把
if (tr[tr[u].l].size + 1 <= size)
写成if (tr[u].size + 1 <= size)
。 pushup
的时候,记得加上if (!u) return ;
防止出现边界错误。- 查询值的排名的时候,是
size(x) + 1
,不要忘记+1
。 - 不要忘记
root = merge(...);
,最好直接分裂合并成对写。 pushdown
不关要写在操作函数,只要是递归了就要写,包括输出函数。
Splay
- yxc写法里面,
insert
的末尾不用pushup(p)
是因为一定会把u
转到根,也就是一定会和p
交换,而交换之后是先pushup(p)
再pushup(u)
,就是正确的了;当然看着难受,可以加上pushup
。 - 查找指定排名的值时,递归右子树,忘记减去左子树和根对大小的贡献。
splay
函数末尾if (!k)
写成if (k ^ 1)
。
2022.12.18
这份代码调了将近2h,终于知到自己打平衡树多难了TQT……
总结一下:
- 但凡手动改变了
tr
数组的值(调用rotate
和splay
函数的不算,因为里面会pushup
),都要手动pushup
一遍; - 同时查询多个值并对树进行修改时,要先全部查询完,再来处理修改,不然第二个查询的值就不是原树的值了,而是进行了第一个修改的值(比如上面代码的
Top/Bottom
操作的两个get_k
)。 - 上面这题的
Insert
操作,相当于交换两个节点的位置,很值得学习,忘记写tr[v].p=0
,但是其实只要照着结构体的每个变量,一个个按照新树的结构进行交换,是可以避免忘记写的。
2022.12.24
Splay找前驱和后继的时候不用很麻烦的递归,因为这样还要考虑父节点是不是后继。可以直接把要求前驱后继的点x
转到根,这样就没有父结点了,直接左儿子向右走,右儿子向左走就行了。
2022.12.26
here,看注释。
插入一段区间之后一定不要忘记Splay是双向链表,有一个p
的值要更新。