zoukankan      html  css  js  c++  java
  • 【总结】伸展树

    伸展树是一枚二叉树,可以维护一个数列,或者可以作为二叉搜索树,因为无论怎么旋转,它的中序遍历是不变的。

    1、伸展操作。

    Splay(x,goal):旋转结点x,使它成为结点goal的儿子。

    至于旋转,本质上只有左旋和右旋。

    2、插入。

    如果作为二叉搜索树,则插入与二叉搜索树一样,最后把该结点旋转到根。

    如果用于维护一个数列,要求在x位置之前插入val(val可以为一个数字或一个序列),则将第x-1个结点旋转到根,将第x个结点旋转到第x-1个结点的儿子,那么根据中序遍历,val应插入在第x个结点的左儿子。

    3、删除。

    与插入同理。

    4、Select(k)。

    在二叉搜索树中,对每个结点维护一个num值,如果x左儿子的num+1=k,x就是第k小的数。

    在维护序列中,显然就是第k个数。

    5、翻转。

    区间:将第a-1个数旋转到根,将第b+1个数旋转到a-1的儿子,那么b+1的左子树就是区间[a,b]。

    在b+1的左儿子标记翻转,像线段树一样延迟标记,延迟标记往下推的时候交换左右儿子。

    6、循环平移。

    序列:1、2、3  --循环左移一位后->   2、3、1。

    本质上就是两个区间的交换。

    坑爹的地方:

    1、下标为0的结点作为边界,它的pre、next值被乱搞没关系,但是它维护的数值(比如 num,max,min...)不能影响到要维护的数列。

    2、区间翻转,则左右儿子交换,可能左右儿子维护的值也需要交换。

    3、不断的删除和插入一段序列时,可能会爆内存,删除的时候只好把删除的结点压到栈里,循环利用。

    4、区间操作时,可以在序列的两端加入两个边界结点1和n+2。避免讨论,但它维护的数值不能影响到要维护的数列。

    【HYSBZ】1588 营业额统计

    数据有问题,用Splay实现很裸的二叉搜索树。

    【POJ】3481 Double Queue

    依然是Splay实现二叉搜索树。

    【HYSBZ】1503 郁闷的出纳员

    依然是Splay的操作。如果在平衡树中维护一段区间,蛋就碎了。

    I命令:立刻离开不算入离开公司的员工的总数。

    可以把数据分成两部分,在Splay中的部分,和待加入平衡树的部分。

    把Splay中的数据同时加上val(val可能为负),相当于把待加入Splay的部分同时减去val,因为两个部分数据的相对值不变。

    S命令:删除Splay中小于相对标准的子树。

    【HDU】1754 I Hate It

    Splay维护区间最值。

    线段树是一个区间平分为两个子区间。

    Splay根据中序遍历,把一个区间分为左、中、右。

    维护上大同小异。

    【HDU】3487 Play with Chain

    删除、插入、翻转,之前扯淡过了。

    【HYSBZ】1500 维修数列

    修改、求和、最大连续子序列和、都和线段树一样,翻转的时候左右连续的最大和要交换。

    【POJ】3580 SuperMemo

    循环移动T次,T>0表示左移,T<0表示右移。取模以后都转换成左移即可。

    【HDU】2475 Box

    很容易想到,5在1内可以把5作为1的儿子,那么可以得到一片森林,而且儿子可能很多。

    那么可以用动态树,其实用Splay也可以做到。

    那么建树完DFS一遍,可以得到一个或者多个括号序列。比如2在1内,3在1内,4在3内就是1 2 2 3 4 4 3 1。

    接下来,可以用Splay维护多个序列。

    询问root的时候,就是该序列的最左端的值。

    移动的时候,就是把一段序列移到另一段序列中。

    【HDU】3726 Graph and Queries

    给出一个无向图,图中每个顶点都有一个权值:

    1、删除一条边;

    2、询问与顶点x连通的顶点中,第k大的值。

    3、改变某个顶点的权值。

    输出所有询问的平均值。

    膜拜ghnjk大神的做法和他的AVL……

    由于删一条边不能确定该图是否边分成两个连通分量,但是加入一条边可以判断是否把两个连通分量连通、或者还是一个连通分量(并查集)。

    所以离线读入所有询问,把每个顶点的权值存入该顶点的邻接表。

    初始时,每个顶点都是一个单独的Splay。

    当合并两个集合时,将两枚Splay合并,由于两枚Splay的值不会总是严格大于对方,所以只好把小的Splay的每个顶点插入到大的Splay中。

    新博客:www.zhixiangli.com
  • 相关阅读:
    Educational Codeforces Round 81 (Rated for Div. 2)(训练)
    Prime Path(POJ) 3126
    前端知识(一)04 Vue.js入门-谷粒学院
    前端知识(一)03 初识 ECMAScript 6-谷粒学院
    前端知识(一)02 初识 Node.js-谷粒学院
    前端知识(一)01 前端开发和前端开发工具-谷粒学院
    同步和异步、阻塞和非阻塞
    给HTML页面设置自己的icon
    解决MyBatis-Plus 3.3.1中自动生成代码tinyint(1)无法自动转换为Boolean 的办法
    驼峰命名和短横线命名的转换
  • 原文地址:https://www.cnblogs.com/DrunBee/p/2646593.html
Copyright © 2011-2022 走看看