关于势能分析

可能有不少不严谨之处,太菜了请谅解。

之前对于 splay 的复杂度一直不是很懂,今天进行了一个势能分析的学习。

势能分析,就是借助势能函数,将中间过程用势能函数来刻画以得到发杂度的一个上界,这样分析出来的一般是均摊复杂度。

例如,第 i 此操作的代价是 ci,那么设第 i 次操作的复杂度 Ci 是:

Ci=ci+ϕ(i)ϕ(i1)

Ci=ci+ϕ(n)ϕ(0)

ciϕ(n)ϕ(0) 存在一个上界,那么我们就算出了一个复杂度的上界。

一些例子:

1. 栈

维护一个栈,支持 pushpopmultipop 三种操作,push 和单次 pop 的复杂度都是 O(1),进行 n 次操作,分析其复杂度。

直觉来看,复杂度是 O(n) 的,怎么证明呢?现定义势能函数 ϕ(i) 为第 i 次操作后栈内元素个数。那么:

  • pushCi=ci+ϕ(i)ϕ(i1)=1+1=2
  • popCi=ci+ϕ(i)ϕ(i1)=11=0
  • multipop(k)Ci=ci+ϕ(i)ϕ(i1)=kk=0

n 次操作,因此复杂度 O(n)

2. 二进制加法

一个二进制数,从 1 加到 n。证明时间复杂度。

定义 ϕ(i) 为第 i 次操作后 1 的个数。

一次加 1 相当于 k10 和一次 01,则:

Ci=ci+ϕ(i)ϕ(i1)=k+1+ϕ(i1)k+1ϕ(i1)=2

一次操作均摊 O(1),总的就是 O(logn)

2.5 一些理解

  • 势能分析的作用,就在于通过设计函数,把时间长的操作拼到时间短的上面。
  • 由上一条的启发,我们得到一个设计函数的思路:执行时间长的操作时,势能一般是降低的,时间短的操作时反之。
  • Ci=ci+ϕ(i)ϕ(i1),中间的代价和势能之间的相加有什么意义吗?其实这没有任何实际意义,只是我们利用其来进行一个平衡。

3. Splay

现在要设计一个势能函数,根据我们的直觉,势能函数理应与 Splay 的平衡有关。

下面记 |x|x 子树的大小。

若一 n 个点的 Splay 进行了 mSplay 操作。
ϕ(i)=log(size(i)),整棵 Splay 的势能函数 Φ(T)=ϕ(x)

则一次旋转的代价为 Ci=O(1)+ΔΦ(T)

设要旋转的节点为 x,其父亲和父亲的父亲分别为 yz,那么:

  • 进行一次 zig 操作时:

Ci=1ϕ(x)ϕ(y)+ϕ(x)+ϕ(y)=1+ϕ(y)ϕ(x)1+ϕ(x)ϕ(x)

  • 进行 zig-zag 操作时:

Ci=1ϕ(x)ϕ(y)ϕ(z)+ϕ(x)+ϕ(y)+ϕ(z)=1+ϕ(y)+ϕ(z)ϕ(x)ϕ(y)

然后进行一个神秘的放缩:

因为旋转后

|x|>|y|+|z|

因此

ϕ(z)+ϕ(y)2ϕ(x)<1

所以

Ci=1+ϕ(y)+ϕ(z)ϕ(x)ϕ(y)ϕ(y)+ϕ(z)ϕ(x)ϕ(y)(ϕ(z)+ϕ(y)2ϕ(x))=2ϕ(x)ϕ(x)ϕ(y)2(ϕ(x)ϕ(x))

  • 进行 zig-zig 操作时:

Ci=1ϕ(x)ϕ(y)ϕ(z)+ϕ(x)+ϕ(y)+ϕ(z)=1+ϕ(y)+ϕ(z)ϕ(x)ϕ(y)

又因为

(1)|x|=|x|+|z|+1

因此

ϕ(x)+ϕ(z)2ϕ(x)=log|x||z||x|<log|x|4|x|=2<1

代换得:

Ci=1+ϕ(y)+ϕ(z)ϕ(x)ϕ(y)=ϕ(y)+ϕ(z)ϕ(x)ϕ(y)(ϕ(x)+ϕ(z)2ϕ(x))ϕ(x)+ϕ(z)ϕ(x)ϕ(x)(ϕ(x)+ϕ(z)2ϕ(x))=3(ϕ(x)ϕ(x))

  • 如果 zig-zig 操作两次都转的是 x 的话,(1) 式就不在成立,我们也很难通过放缩把那个 O(1) 消掉,那复杂度就不对了。

综上,除了最后一次旋转外,其余的常数都被我们消掉了。因此一次 Splay 复杂度为 O(1)+3(ϕ(root)ϕ(x0))<3logn

m 次操作,总复杂度为 mlogn+ΔΦ(T)=(m+n)logn

4. LCT

LCT 的复杂度只来源于 Access 操作,因为单独的 Splay 操作是严格小于 Access 中的多次 Splay 的。(应该是的吧?)

沿用对 Splay 的势能分析,对于 Access 中的第 iSplay

Ci=O(1)+3(ϕ(rooti)ϕ(xi))

因为 ϕ(rooti) 一定小于 ϕ(xi+1),因此:

Ci<k+ϕ(root)ϕ(x0)<k+logn

其中 k 是换链次数,现在只需要证明 k 的复杂度就好了。证明过程非常神奇:

对原树重链剖分,现在边有了轻重之分。

记势能函数 Φ(T) 为整棵树中重虚边的数量。那么在一次 Access 操作中:

  1. 重实边切成轻实边,Φ(T) 增加 1
  2. 轻实边切成重实边,Φ(T) 减少 1

注意到一个点到根的路径中最多经过 logn 条轻边,因此 Φ(T) 最多增加 nlogn 次,相应地切边最多也只有 nlogn 级别。

这样我们就用势能分析证明了 LCT 的复杂度。

(其实我们也顺带证明了假如说用 fhqTreap 来维护的话复杂度为什么是 nlog2n 的,因为一棵 fhqTreap 只保证了深度为 logn,并不能像 Splay 一样看成一个整体来看待。

参考资料

Splay 树 - OI Wiki
势能分析 - Achtoria - 博客园

本文作者:KIreteria

本文链接:https://www.cnblogs.com/11-twentythree/p/18355623

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   KIreteria  阅读(43)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起