Skip to content
liuenyin's blog
Go back

三月七树

Edit page

主要是一个有点乐子的数据结构,并不是最优解法。

更新:三月七树也可以维护序列(可以替代线段树,单次 logn\log n,还可以支持序列插入删除等,加上这个的复杂度为 m\sqrt m)。

省流:一种基于暴力重构的平衡树。

优点:常数小,好写好调好理解。

缺点:在特定数据下复杂度差。


约定 nn 为总元素个数,mm 为总操作次数,BB 为块长。

平衡树的一般操作可见这里

我们注意到普通的二叉搜索树各操作的复杂度为 O(h)O(h)hh 为树高,各种平衡树只是通过很多操作保证了 hlog2nh≈\log_2 n,但这些操作大多很复杂。在这里,引入一种基于分块的方便的处理方式。我将其称为“三月七树”。

我们记录当前树高 hh。在执行操作 11 时,hh 有概率变大。当 hBh\ge B 时, 我们将整棵树进行一次 DFS 。由于二叉排序树的性质,进行中序遍历的结果一定是排好序(从小到大)的,我们按照这个顺序将其记录下来。随后,对这个序列进行建树。考虑到(可能是我不知道)二叉排序树并没有什么快速建树的方法,我们对这个序列(依照有点类似树状数组的方式)建树,具体如下:

对于第 ii 个元素,令其位于从下往上kk 层(钦定叶子节点为 00),kk 为满足 2xi2^x|i 的最大整数。然后,若 klog2nk\le \log_2 n,向第 k+1k+1 层没有同时拥有左右子结点的节点连边。若该节点不存在,分两种情况:若下一个 k+1k+1 层的节点理应小于 nn,向这个节点连边。否则,向第 k+2k+2 层节点连,若仍不存在,再次重复上述判断。

下面是 n=17n=17 时建出来的树。编号为这个元素的排名。

(9 和 11 号节点画反了,但是不太影响总体)

通过这种方式重构三月七树的复杂度为 O(n)O(n) 的。以下为证明:

显然,对于某个确定的 iikk 是可以 O(1)O(1) 求出的。向 k+1k+1 层连边的复杂度为 O(1)O(1)。在我们首次向 k+2k+2 层连边后,不可能再次向 k+1k+1 层连边,因为在这种情况下,k+2k+2 层的节点排名一定在 k+1k+1 层之前,那么向上的过程是单调的。复杂度为 n+log2n=O(n)n+\log_2 n=O(n)

重构后 h=log2nh=\log_2 n

其他操作与普通二叉树极度相似,不再赘述,同时因此三月七树的期望单次操作复杂度为 O(logn)O(\log n)

以下为最坏复杂度分析。

最坏情况下,输入单调。因此会出现最左(右)链特别长的情况。这种情况下单次操作最坏为 O(h)=O(B)O(h)=O(B),如果一直这么做,每 Blog2nB-\log_2 n 次会进行一次重构。复杂度为 O(nmBlog2n+mB)O(\dfrac{nm}{B-\log_2 n} +mB),前一项为重构复杂度。取 B=nm+log2nB=\dfrac{n}{\sqrt m}+\log_2 n(或还可以取 m\sqrt m 等),带入进去得到最坏复杂度 nmBlog2n+mB=mm+mm+mlog2n=O(m(m+logn))\dfrac{nm}{B-\log_2 n} +mB=m\sqrt m+m\sqrt m+m\log_2 n=O(m(\sqrt m+\log n))。够不到普通平衡树的水平,但是也达到分块了(还能简单的实现插入删除)。有点鸡肋,但是似乎有点用。大概可以稳定通过 n,m2×105n,m\leq 2\times 10^5 的构造数据。

或许子树内重构可能比整棵树重构更优达到更好的复杂度?有兴趣的朋友可以研究研究。


Edit page
Share this post on:

Previous Post
2025.7.9 高铁上记录
Next Post
做题笔记