zoukankan      html  css  js  c++  java
  • 动态树之link-cut tree

    说好的专题。。。

    lct的一些概念看论文 杨哲《QTREE解法的一些研究》 简单易懂。

    首先不要把lct想象得很难,其实很水的。lct就是很多splay树维护的树。。。

    lct的access操作就是在原树中拓展一条点到根的类二叉树出来(用splay来维护)

    这里,splay树是按深度作为关键字的,当然,在无向图中(无环)可以任意指定一个点为根,这点要切记(因为在这里操作时,有些操作需要换根,所以一定要理解)

    link操作就是将点作为这颗类二叉树的根,然后合并

    cut操作就是将点作为这颗二叉树的根,然后在拓展一条另一个点的splay路径(此时这两个点一定要有边连接,这样使得拓展上来的根一定在另一个点拓展上来的splay树的左子树上,因为他们有边连接),将左子树的父亲设为0,并且去掉左子树

    getroot操作就是将点拓展了splay后,并且将它伸展到根,此时,最小的子树(深度最浅,即最左的子树)就是这颗splay的根

    makeroot操作就是将点拓展为现在所在的树的根,即换根,伸展到根后只需要将左右子树反向,就是将深度换了(根据splay有良好的下放操作,我们将翻转用标记来翻转,使得时间复杂度减小)

    split操作就是将两个点的路径拓展出来进行操作,即makroot(x); access(y); splay(y);

    额,我自己都觉得说得不好 。。囧

    说些注意的地方吧:

    1. 在维护splay树时,当x为这棵树的根时,并不意味着它没有父亲,只是他的父亲没有这个孩子(这点一定要理解!!),因为我们维护的是一棵多叉树,但是我们拓展的是二叉树,所以,你懂的。怎么修改呢,在原来splay操作的判null的地方都用现在的特判。
    2. 在旋转时,还需要判断父亲的父亲是否为上边所说的那样,如果是,就不要更新他,因为这两个点不在一颗splay上。
    3. splay操作时,下放标记我们要用一个栈到达他的根往下放标记。(因为每个点进行操作时,祖先的tag必须已经全部下放过。而lct是多颗splay树,是按深度排序的,会导致splay的节点祖先都还没有下放过标记。)
    4. 每一次更新节点操作,都要splay至树根再操作,理由和上边差不多。因为可能在询问路径时,之前更新过的节点是在那棵splay树的靠右的地方,导致在原树中浅的节点没有得到更新。(不懂请q我或看例题5)
    5. 不要把splay和原树搞混。
    6. 不要认为只有一颗splay树。
    7. 不要认为理所当然,,,在思考的时候好好思考。

    好了,我认为差不多了。。

    一些题我之前也发了博文,我现在再放出来。。

    例题:

    1. 【BZOJ】2002: [Hnoi2010]Bounce 弹飞绵羊
    2. 【BZOJ】1036: [ZJOI2008]树的统计Count
    3. 【BZOJ】2049: [Sdoi2008]Cave 洞穴勘测
    4. 【BZOJ】3282: Tree(lct)
    5. 【BZOJ】1180: [CROATIAN2009]OTOCI & 2843: 极地旅行社(lct)(在这里可以找到注意事项4的原因)
    6. 【BZOJ】3669: [Noi2014]魔法森林(lct+特殊的技巧)
  • 相关阅读:
    剑指 Offer 06. 从尾到头打印链表
    剑指 Offer 05. 替换空格
    剑指 Offer 04. 二维数组中的查找
    14. 不修改数组找出重复的数字
    剑指 Offer 03. 数组中重复的数字
    231. 2 的幂
    1394. 完美牛棚
    10. 正则表达式匹配
    3726. 调整数组
    474. 一和零
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/3919083.html
Copyright © 2011-2022 走看看