平衡树与finger search
1.复杂度分析
Treap
定理1:$n$个节点的Treap的期望深度为$o(\log n)$
证明1:假设所有元素从小到大依次为$a_{1},a_{2},...,a_{n}$(不妨假设所有元素各不相同,若有相同可以将这些元素存在同一个位置上),则对于$x$和$y$,分类讨论:
1.若$x\le y$,则$x$是$y$的祖先等价于$a_{x}<\min_{x<j\le y}a_{j}$
2.若$x>y$,则$x$是$y$的祖先等价于$a_{x}<\min_{y\le j<x}a_{j}$
(这里要求随机权值构成小根堆,且不妨假设随机权值各不相同)
这件事的概率也就是$x$权值最小的概率,即$\frac{1}{|x-y|+1}$
$x$的深度也可以定义为$x$的祖先数,而其期望祖先数即为$\sum_{i=1}^{n}\frac{1}{|x-i|+1}\sim o(\log n)$
这是论文中给出的证明,但其实并不太严谨,这里再给出一种证明方式——
证明2:令$T(n)$为$n$个节点的Treap的期望深度,考虑枚举其中随机权值最小的点(作为根),即
$$
T(n)=n+\frac{\sum_{i=1}^{n}T(i-1)+T(n-i)}{n}=n+\frac{2}{n}\sum_{i=0}^{n-1}T(i)
$$
类似地,将$n-1$的式子写出后两式相减,即
$$
T(n)-T(n-1)=1+\frac{2}{n}\sum_{i=0}^{n-1}T(i)-\frac{2}{n-1}\sum_{i=0}^{n-2}T(i)\le 1+\frac{2}{n}T(n-1)
$$
简单化简后,即
$$
\frac{T(n)}{n+1}\le \frac{1}{n+1}+\frac{T(n-1)}{n}\le \frac{1}{n+1}+\frac{1}{n}+\frac{T(n-2)}{n-1}\le ...\le \sum_{i=2}^{n+1}\frac{1}{i}\sim o(\log n)
$$
于是,即$T(n)\sim o(n\log n)$,即所求证
Splay
定理2:对一个$V$个节点的伸展树执行$n$次Splay操作的复杂度为$o((V+n)\log V)$
证明:对于一棵伸展树$T$,定义节点$x$的势能函数为$r(x)=\log sz_{x}$(其中$sz_{x}$为其子树大小),则$T$的势能函数为$\varphi(T)=\sum_{x}r(x)$(其中$x$为$T$中的节点)
假设第$i$次操作后的Splay为$T_{i}$(特别的,$T_{0}$为初始的伸展树),第$i$次操作复杂度(旋转次数)为$a_{i}$,则第$i$次操作的均摊复杂度记为$b_{i}=a_{i}+R(T_{i})-R(T_{i-1})$,后者记为$\Delta_{\varphi}(i)$
综上,总复杂度即
$$
\sum_{i=1}^{n}a_{i}=\sum_{i=1}^{n}b_{i}+R(T_{0})-R(T_{n})\le \sum_{i=1}^{n}b_{i}+V\log V
$$
下面,我们只需要考虑$b_{i}$即可,对Splay中的三类情况分开讨论:
(为了方便,假设执行$Splay(k)$,且$fa$为$k$的父亲,$ga$为$k$的祖父,带$'$为旋转后的$T_{i}$)
1.单旋,其使得$b_{i}$增加$1+r'(fa)-r(k)\sim o(\log V)$
2.三点一线时,先旋转$fa$,再旋转$k$,其使得$b_{i}$增加
$$
1+r'(fa)+r'(ga)-r(k)-r(fa)\le 1+r'(k)+r'(ga)-2r(k)
$$
根据$sz'_{k}=sz_{k}+sz'_{ga}+1$,有$2r'(k)-r(k)-r'(ga)\ge \log \frac{(sz_{k}+{sz'_{ga}})^{2}}{sz_{k}sz'_{ga}}\ge 2$
将$2r'(k)-r(k)-r'(ga)-2\ge 0$加入上式,即有
$$
1+r'(k)+r'(ga)-2r(k)+2r'(k)-r(k)-r'(ga)-2\le 3(r'(k)-r(k))
$$
3.三点不一线时,旋转两次$k$,类似地也可以证明其使得$b_{i}$增加不超过$3(r'(k)-r(k))$
注意到$r'(k)$可以与下一次的$r(k)$相消,因此第2类和第3类总增加量不超过$3(r'(k)-r(k))\sim o(\log V)$
综上,即对于初始为0的$b_{i}$,增加总量也不超过$o(\log V)$,即$b_{i}\sim o(\log V)$
将之代入,不难得到复杂度为$o((V+n)\log V)$,即所求证
2.Treap的可持久化和树套树
可持久化
所有非均摊的数据结构基本都是可以可持久化的
论文中提到了关于Treap中可持久化不能直接复制随机值,而是在比较时进行随机判定是否旋转,并且旋转$k$的概率为$\frac{sz_{k}}{sz_{fa}}$($fa$为$k$的父亲)
(我觉得或许直接复制随机值应该也是对的吧)
树套树
事实上,旋转的Treap也是可以实现树套树的
定理3:若一次旋转$k$的复杂度为$o(sz_{k})$,则Treap单次插入操作期望复杂度为$o(\log n)$
证明:假设插入$k$,当$k$旋转后$k$必然是其子树中权值最小的点,这样的概率是$\frac{1}{sz_{k}}$,那么这次旋转的期望复杂度即为$o(1)$,也可以看作这个节点对答案的期望贡献为$o(1)$
又因为前面说明树高为期望$o(\log n)$,而只有$k$到根路径上的点对答案会有期望$o(1)$的贡献,总复杂度即期望$o(\log n)$,结论成立
定理4:若一次重构$k$子树时间复杂度$o(sz_{k}\log sz_{k})$,则Treap单次删除期望复杂度为$o(\log n)$
证明:由于Treap是随机的,删除节点的子树大小可以看作一个节点的期望子树大小
由于树高$o(\log n)$,因此所有节点子树大小之和为$o(n\log n)$,显然期望子树大小为$o(\log n)$,将其子树暴力重构即可,对于$o(\log\log n)$的复杂度可以忽略,即复杂度为期望$o(\log n)$
上面所给的旋转以及重构的复杂度,也就是平衡树套序列的复杂度(每一个节点维护子树内所有元素所构成的序列),也就可以做到$o(n\log n)$
而对于平衡树套权值线段树,此时插入和删除相较于上面两者也就多了一个$\log n$,复杂度即$o(n\log^{2}n)$,与替罪羊树相同,也是可以接受的
(树套树中的线段树不能互相嵌套,因此重构不能使用线段树合并,仍是$o(sz_{k}\log sz_{k}\log n)$的)
3.Finger Search
Finger Search
关于Finger Search,即在一个数据结构中,令$d(x,y)$为在$x$和$y$之间的元素个数(包括$x$和$y$),当已经确定$x$的位置后,可以在$o(\log d(x,y))$的时间内快速查询$y$的操作
(另外下面还将考虑Finger Search的简单拓展,即快速插入和删除)
显然并不是所有数据结构都能支持Finger Search,下面分别来考虑Treap和Splay
Treap
定理5:在Treap上,$x$到$y$的路径长度为期望$o(\log d(x,y))$
证明:注意到$x$到$y$的路径长度即是$x$祖先且不是$y$祖先的节点数+是$y$祖先且不是$x$祖先的节点数,根据对称性可以仅考虑前者
假设Treap所有元素从小到大依次为$a_{1},a_{2},...,a_{n}$,其中$a_{i}=x$且$a_{j}=y$,显然$d(x,y)=j-i+1$
考虑一个节点$a_{k}$,求出其满足“是$x$祖先且不是$y$祖先”的概率,将其累加即可
根据前面定理1的证明,我们需要对$k$分类讨论:
1.$1\le k\le i$,这等价于$k$是$[k,i]$的最小值且$[k,i]$的最小值大于$(i,j]$的最小值,前者概率为$\frac{1}{i-k+1}$,后者概率为$\frac{j-i}{j-k+1}$,相乘后即$\frac{j-i}{(i-k+1)(j-k+1)}$
注意到这就是$\frac{1}{i-k+1}-\frac{1}{j-k+1}$,累加后即
$$
\sum_{k=1}^{i}\frac{1}{k}-\sum_{k=j-i+1}^{j}\frac{1}{k}=\sum_{k=1}^{i}\frac{1}{k}-(\sum_{k=1}^{j}\frac{1}{k}-\sum_{k=1}^{j-i}\frac{1}{k})\le \sum_{k=1}^{j-i}\frac{1}{k}\sim o(\log d(i,j))
$$
2.$i<k<j$,类似地概率为$\frac{j-k}{(k-i+1)(j-i+1)}=\frac{1}{k-i+1}-\frac{1}{j-i+1}$,累加后即$\sum_{k=1}^{j-i+1}\frac{1}{k}-1\sim o(\log d(i,j))$
由此,在Treap上再维护一个子树最小值和最大值,暴力从$x$向父亲爬去找$y$即可实现Finger Search
下面来考虑Finger Search的拓展,对于插入:根据定理3,可以发现Treap插入的瓶颈事实上就在于寻找位置,更具体的,我们有以下定理——
定理6:Treap单次插入操作期望旋转次数为$o(1)$
证明:根据定理3的证明,一个点期望旋转次数,即其到根所有节点子树大小倒数之和
而所有点期望旋转次数之和,考虑一个点的贡献,不难发现恰好为1,即总和期望为$o(n)$,那么其中一点期望次数为$o(1)$,即所求证
那么找到位置后,再以$o(1)$次旋转即可,即实现了Finger Search的插入
对于删除:Treap的删除需要将该节点旋转到子树叶子,根据定理4这一部分也就是$o(\log\log n)$,也可以忽略,那么同样也可以支持删除
综上,Treap需要通过一些技巧来支持Finger Search即其拓展
Splay
在Splay中,由于每一次会将上次所插入、删除或查询的Splay到根,实际上也就是实现了Finger Search,更具体的来说,可以有以下结论——
定理7(Dynamic Finger Theorem):对于一个$n$个点的Splay,进行$m$次操作,每一次操作的元素为$a_{i}$(特别的,$a_{0}$定义为初始Splay中的根),则复杂度为$o(n+m+\sum_{i=1}^{m}\log d(a_{i-1},a_{i}))$
这个定理的证明比较复杂,这里就省略了
根据这个结论,也就说明Splay可以不需要附加其他操作来支持Finger Search即其拓展
4.Treap的快速合并和分裂
合并
考虑合并两颗Treap,分别为$T_{1}$和$T_{2}$(假设大小分别为$n$和$m$,且$T_{1}$中的权值严格小于$T_{2}$),普通的合并也就是FHQ Treap,合并复杂度为$o(\log n+\log m)$
事实上,Treap的合并还可以进一步优化,达到$o(\log \min(n,m))$的复杂度
具体来说(不妨假设$n>m$),在合并的递归过程中,一开始会又连续较多次都是以$T_{1}$的根为根并将右儿子与$T_{2}$合并,这些过程完全可以将最后一次与$T_{2}$合并
更具体的,考虑从$T_{1}$中的最大值开始(也就是从根不断向右儿子移动),不断向父亲移动,直至父亲的随机权值小于$T_{2}$根节点的随机权值时停止,并将当前节点与$T_{2}$合并并作为父亲的右儿子
(这里的合并就是普通的合并,即做到$o(\log n+\log m)$的复杂度)
$m$显然是不变的,现在来考虑$\log n$,也可以看作最大值移动的次数
最终这个位置将会被$T_{2}$的根替代,而这条链并不会被压缩,也就是说最终合并后$T_{2}$的根到$T_{1}$中最大值的路径长度严格大于移动的次数,根据定理5可以得到是期望$o(\log m)$的
$n<m$类似,也就是会有较多次将$T_{1}$与$T_{2}$的左儿子合并,同样可以证明复杂度为期望$o(\log n)$
(当然,具体实现中可以更方便的直接自底向上进行合并,这里只是为了说明其实际意义)
分裂
对于一个大小为$n+m$的Treap(记作$T$),普通的分裂也是FHQ Treap,分裂复杂度为$o(\log (n+m))$
Treap的分裂也可以优化,假设拆出两颗大小为$n$和$m$的子树(分别为$T_{1}$和$T_{2}$,且$T_{1}$中的权值严格小于$T_{2}$),则分裂也可以优化到$o(\log \min(n,m))$的复杂度
类似合并,在分裂的过程中,会有很长时间都在向同一边拆分
更具体的,分裂有两种,先来考虑给出排名(也就是$n$和$m$)的方式:
不妨假设$n>m$,从最大值出发去找到值所在的位置,根据定理5可以在$o(\log m)$的时间内找到对应权值以及位置,同时还可以求出最大值与该权值的lca
在这个lca之前,显然都会被分到$T_{1}$,因此可以直接在这个lca内部进行划分
此时递归的深度即与最后$T_{2}$的深度相同,为期望$o(\log m)$
$n<m$也是类似的,从最小值去找该值即可
但如果分裂给出的是权值,由于无法确定$n$和$m$的关系,仅是查找该节点就会退化为$o(\log (n+m))$
这时候还有一个方法,从最小值和最大值同时去找这个权值,且双方每一次各移动一步,那么找到时所花的步数也就是期望$o(\log \min(n,m))$,也就与其相同
启发式合并
启发式合并就不能保证权值有严格的关系,因此对于这样两颗大小为$n$和$m$的Treap(不妨假设$n>m$),通常都是以$o(m\log n)$的复杂度来完成合并的
总得来说,将$n$个大小为1的Treap以此法启发式合并的复杂度为$o(n\log^{2}n)$
但是,我们可以将较小的Treap中的权值从小到大插入,此时借助Finger Search的插入拓展,似乎可以优化复杂度,具体来说有以下定理——
定理8:以上述方式启发式合并$n$个大小为1的Treap,复杂度为$o(n\log n)$
证明:先来考虑以此法合并大小为$n$和$m$($n>m$)的Treap的复杂度,也就可以看作求将$n$划分为若干个数,每一个数的$\log$之和
根据$\log$函数的凸性,不难调整证明均匀划分时复杂度最低,即单次插入复杂度为$o(\log \frac{n}{m})$
接下来,考虑每一个数的贡献:
假设其执行插入操作$k$次,第$i$次插入到的子树大小(指合并结束后)依次为$a_{i}$(特别的,$a_{0}=1$),由于$a_{i-1}$恰好是上一次的$m$,因此其贡献即$\sum_{i=1}^{k}\log\frac{a_{i}}{a_{i-1}}=\log a_{k}\sim o(\log n)$
所有节点贡献之和即为$o(n\log n)$,也就是复杂度
关于Splay
在上述操作中,Splay也可以支持部分操作:
1.快速合并,将较小的Splay的最小或最大值Splay到根,虽然这样合并看上去会增加$\log \max(n,m)$的势能,但如果我们修改势能的定义,将其定义为所有非根节点势能和,还是可以做到均摊$o(\log \min(n,m))$的复杂度
2.启发式合并,根据定理7可以证明其与Treap以此法启发式合并的复杂度相同,即也可以做到$o(n\log n)$
3.对于分裂操作,需要将该节点Splay到根是$o(\log (n+m))$的,似乎无法支持