• LCT 的基本操作


    一 点睛

    LCT 有 7 种基本操作

    • access(x) 

    • makeroot(x) 

    • findroot(x)

    • split(x , y)

    • link(x , y)

    • cut(x , y)

    • isroot(x)

    二 access(x)

    1 定义

    access(x) 是动态树所有操作的基础,用于打通 x 到原树根节点的一条实链。

    2 图解

    a 原树变化

    access(L) 指将 L 到树根的路径变为实链,这条实链上的节点 L、I、F、C、A 与其他子节点的边变虚边,原树的变化如下图所示。

    b LCT 变化

    (1)将 L 旋转为所在伸展树的根,将 L 的右儿子置空(相当于变虚边)。

    (2)将 L 的父节点 I 也旋转到所在伸展树的根,将 I 的右儿子置为 L。

    (3)将 I 的父节点 A 也旋转到所在伸展树的根,将 A 的右儿子置为 I。此时,A-C-F-I-L 是一条实链,由一棵伸展树维护(按节点在原树中的深度,中序有序),如下图所示。

    三 makeroot(x)

    1 定义 

    将指定的点 x 换成原树的根。

    2 换根操作

    ① access(x),打通一条 x 到原树根的实链。

    splay(x),将 x 旋转为所在伸展树的根。

    ③ reverse(x),反转当前伸展树的左右子树。

    3 图解

    (1)access(L),得到一条 L 到原树根的实链,此时 L 在该实链中深度最大。原树和 LCT 的变化如下图所示。

    (2)splay(L),将 L 旋转为所在伸展树的根,在原树中,L 是该实链上深度最大的节点,因此在当前伸展树中,L 没有右子树。

    (3)reverse(L)。在原树中,树根的深度最小,于是反转当前伸展树的左右子树,使所有节点的深度都倒过来,原来按照深度递增形成的序列为 A-C-F-I-L,反转后按照深度递增形成的序列为 L-I-F-C-A。此时 L 没有左子树,反倒成了深度最小的点(根节点)。

    四 findroot(x)

    1 定义

    findroot(x) 表示查找 x 所在原树的树根,主要用来判断两点之间的连通性。若 findroot(x) = findroot(y),则表明x 、y 在同一棵树中。

    2 操作步骤

    ① access(x),打通一条 x 到原树根的实链。

    ② splay(x ),将 x 旋转为所在伸展树的根。

    ③ 查找当前伸展树的最左节点(深度最小的点,即树根),返回根节点即可。

    3 图解 

    原树及对应的 LCT 如下图所示,求 L 所在原树的树根 findroot(L),操作过程如下。

    执行 access(L)、splay(L) 之后的 LCT 如下图所示。

    当前伸展树的最左节点为 A(深度最小的点,即树根),返回根节点 A 即可。

    五 split(x , y)

    1 定义

    split(x , y) 表示分离出 x -y 的路径为一条实链,用一个伸展树维护。

    2 分离步骤

    ① makeroot(x),将 x 变成原树的根。

    ② access(y),打通一条 y 到原树根的实链。

    ③ splay(y ),将 y 旋转到当前伸展树的树根。

    3 图解

    原树及其对应的 LCT 如下图所示,分离出 L-B 的路径,操作过程如下。

    (1)makeroot(L),将 L 变为原树的树根,对应的 LCT 如下图所示。

    (2)access(B),打通 B 到根的一条实链,这条实链的中序序列正好是原树中 L-B 的路径 L-I-F-C-A-B,对应的 LCT 如下图所示。

    (3)splay(B),将 B 旋转到当前伸展树的根,对应的 LCT 如下图所示。

    六 link(x , y)

    1 定义

    link(x , y) 表示在 x 、y 之间连接一条边。若 x 、y 之间连通,则不可以连边。

    2 操作步骤

    ① makeroot(x) 将 x 变成原树的根。

    ② 将 x 的父节点修改为 y,fa(x)=y。

    3 图解

    例如,两棵原树和对应的 LCT 如下图所示,在 B、H 之间连接一条边,操作过程如下。

    (1)makeroot(B),将 B 变为原树的树根,对应的 LCT 如下图所示。

    (2)fa[B]=H,将 B 的父节点修改为 H,相当于在 LCT 中连接了 B-H 的一条虚边,对应的 LCT 如下图所示。

    七 cut(x , y)

    1 定义

    cut(x , y) 表示将 x -y 的边断开(删边)。若 x、y 之间不连通,则不可以删边。若 x、y 之间连通,则还要判断两者之间是否有边,因为连通只代表有一条通路,中间可能有节点。

    2 操作步骤

    ① split(x , y),分离出 x-y 的路径为一条实链,若 x 不是 y 的左儿子或 x 有右子树,则说明 x 到 y 之间有其他节点,不能删边。

    ② 将 x-y 的边断开,修改 y 的左儿子为 0,y 的左儿子的父节点为 0。

    ③ update(y),更新 y 的相关信息。

    3 图解

    原树及对应的 LCT 如下图所示,将 B-D 的边断开,操作过程如下。

    (1)split(B, D) 分 3 步

    ① makeroot(B) 

    ② access(D)

    ③ splay(D)

    (2)双向断开 B-D 的连接。

    八 isroot(x)

    isroot(x) 表示判断 x 是否为所在伸展树的根。注意:伸展树的根和原树的根不是一回事。若 x 是所在伸展树的根,则 x 与其父节点之间是一条虚边,x 既不是其父节点的左儿子,也不是其父节点的右儿子。例如,原树及对应的 LCT 如下图所示,N 是其所在伸展树的树根,既不是其父节点I的左儿子,也不是右儿子;F 是其所在伸展树的树根,既不是其父节点 A 的左儿子,也不是右儿子。A 没有左右儿子,A 和 F 之间的虚边仅说明 F 的父节点是 A,A 却不把 F 当作儿子,即“认父不认子”。

  • 相关阅读:
    Java不支持协程?那是你不知道Quasar!
    超详细BootLoader原理分析
    【雷达通信】SAR雷达系统反设计及典型目标建模与仿真实现研究——目标生成与检测(Matlab代码实现)
    Android 12 DreamCamera2 默认关闭HDR
    【动态规划】--买卖股票的最佳时机
    腾讯云轻量服务器Windows系统使用IIS实现公网直链访问文件
    计算机键盘用途及快捷键
    java毕业生设计中医药科普网站计算机源码+系统+mysql+调试部署+lw
    「6.18福利」精选大厂真题|笔试刷题陪伴|明天正式开屋啦 - 打卡赢价值288元丰厚奖励
    ASP.NET Core 6框架揭秘实例演示[30]:利用路由开发REST API
  • 原文地址:https://blog.csdn.net/chengqiuming/article/details/127861323