压位trie

一种亚 log 数据结构。

在 01trie 二叉树的基础上,变成 \(w\) 叉树,一般取 \(w=64\) 方便用 ull 存储子树是否存在的情况。

支持查询前驱后继最小最大值和插入删除,复杂度都是 \(O(log_{w}V)\) 的,一般的 \(10^9\) 值域也就是 \(5\) 左右的常数。和堆相比功能强大,复杂度也小很多。常用于奇怪的不正确复杂度算法的卡常(如带 \(\log\) 莫队加上这个可以看成大常数的 \(n\sqrt{n}\))。

空间上,因为最底下一层儿子不需要存子树是否存在,所以这部分只需要动态开 \(cnt\) 记录出现次数即可。空间复杂度 \(O(n+\frac{V}{w})\)。值域 \(10^9\) 的话就是 \(125MB\) 多一些这个样子。

实现上类似于 01trie,插入删除是简单的,查前驱后继可以从下往上跳,看左/右边是否存在子树,存在就跳进去找最小/大值即可。最小最大值也是简单的。

插入的时候如果不需要存出现次数的计数器,那么可以判断此数是否已经插入。

删除的时候可以看当前的节点是否还有别的子树,有的话就直接结束过程不用向上跳了。

总之是个不难写的东西,因为常用于卡常,写的时候注意多做位运算代替普通运算和剪枝来减小常数。

例:P8078 WC题,\(O(n\sqrt{n} \log n)\) 的暴力莫队是 naive 的,可以用 set 维护。

发现需要支持查前驱后继和对应值,那么实现一个压位 trie 就轻松做到 \(O(n\sqrt{n} \log_{64}n)\) 了。空间也是 \(O(n)\) 的。

因为大多数人都拿的是回滚莫队做的题,而回滚莫队的常数懂的都懂,所以只要压位 trie 实现的常数好就基本能过,至少也能只 T 一两个点。

record

posted @ 2023-03-01 15:23  infinities  阅读(222)  评论(0编辑  收藏  举报