本文发布于洛谷日报,特约作者:tiger0132

原地址

分割线下为copy的内容


[洛谷日报第62期]Splay简易教程

洛谷科技

18-10-0223:31

简介

二叉排序树(Binary Sort Tree)又称二叉查找树(Binary Search Tree),亦称二叉搜索树。

二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:

若左子树不空,则左子树上所有结点的值均小于或等于它的根结点的值;若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;左、右子树也分别为二叉排序树

同样的序列,因为排序不同,可能会生成不同的二叉排序树,查找效率性对就不一定了。如果是二叉排序树退化成一条链,效率就很低。

伸展树(Splay)是一种平衡二叉树,即优化后的二叉查找树。伸展树可以自我调整,这就要依靠伸展操作Splay(x,S),使得提升效率。

多图预警

图片均为原创,协议为CC0,尽量保留原地址。

劼司机的图片风格太赞啦

前置技能

线段树。

变量定义

N:常量,节点个数。

ch[N][2]:二维数组,ch[x][0]代表x的左儿子,ch[x][1]代表x的右儿子。

val[N]:一维数组,val[x]代表x存储的值。

cnt[N]:一维数组,cnt[x]代表x存储的重复权值的个数。

par[N]:一维数组,par[x]代表x的父节点。

size[N]:一维数组,size[x]代表x子树下的储存的权值数(包括重复权值)。

各种操作

chk操作

辅助操作,查询一个节点位于其父节点的方向。

pushup操作

辅助操作,更新size数组的值。

旋转(rotate)

Splay使用旋转保持平衡。所以旋转是最重要的操作,也是最核心的操作。

Splay旋转后,中序遍历和Splay的合法性不变。

比如最开始的树是这样子的:

现在我们想把2号点搞到号点的位置。

那么2下面的子树就有1,3,4,5。一种比较优秀的玩法是这样的:

那么我们可以考虑这么操作:

先把4→2的边改成4→3。再把6→4的边改成6→2。最后把2→3的边改成2→4。

第一次连边

第二次连边

第三次连边

连边前(原图)

旋转操作有四种。自行模拟后发现:

旋转后,父节点会将连向需旋转的该子节点的方向的边连向该子节点位于其父节点方向的反方向的节点。

令x = 该节点, y = par[x], k = chk(x), w = ch[x][k^1],则ch[y][k] = w; par[w] = y;

旋转后,爷爷节点会将连向父节点的边连向需旋转的该节点。

ch[z][chk(y)] = x; par[x] = z;

旋转后,需旋转的该节点会将连向该子节点位于其父节点方向的反方向的子节点的边连向其父节点。

ch[x][k^1] = y; par[y] = x;

综合一下,得到下列代码(可见自然语言是多么的无力):

伸展(splay)

将一个节点一路rotate到指定节点的儿子。

注意,如果该节点、该父节点和该爷爷节点「三点一线」,那么应该先旋转父节点。

此处进行的操作是将3 splay到根节点。

原图

旋转父节点后

旋转自身后

剩下的情况自行模拟(没图片)了。

并且注意处理爷爷节点已经是目标的情况。

find操作

辅助操作,将最大的小于等于的数所在的节点splay到根。

插入(insert)

从根节点开始,一路搜索下去。如果节点存在则直接自增cnt的值。否则新建节点并与父节点连边。

因为新建节点时可能会拉出一条链,所以新建节点后需要将该节点splay到根节点。沿途的rotate操作可以使平衡树恢复平衡。

查询k大(kth)

从根节点开始,一路搜索下去。每次判断要走向哪个子树。注意考虑重复权值。

查询rank(rank)

并不需要专门写操作。将该节点find到根后返回左子树的权值数即可。

前驱(pre)

将该节点find到根后返回左子树最右边的节点即可。

后继(succ)

同理,返回右子树最左边的节点即可。

删除(remove)

显然,任何一个数的前驱和后继之间只有它自身。

令该点的前驱为,后继为。

那么可以考虑把前驱splay到根,后继splay到前驱的右儿子,那么后继的左儿子就是要删除的点。

最后判特判权值数大于的情况即可。

区间反转

考虑线段树维护区间标记的方法,将其移植到Splay即可。

打标记时,将和分别旋转到根节点和根节点右儿子处,那么的左子树即是区间。在其根处打上标记然后在查询大和输出中序遍历时下传标记即可。

// 这张图有点小

区间打标记

平衡树像线段树一样,可以打标记。但是有一个不同点,就是平衡树的每个节点都有权值。所以更新标记时和线段树不一样,要考虑自身节点的权值。

因为Splay可以直接提取指定区间,所以Splay的区间操作在某些意义上比线段树还好写。

例题 P2042 维护数列(https://www.luogu.org/problemnew/show/P2042)

策爷:“splay/块状链表的自虐题。”

看到插入、删除、反转就很容易想到fhq-treapSplay。

简化版问题

如果只考虑修改、求和、求最大子段和,就可以直接用线段树解决。

考虑维护la[N]、ra[N]、gss[N]、sum[N]、upd[N],分别代表最大前缀和、最大后缀和、最大子段和、区间和和修改标记。

初始化la、ra时,在选与不选之间取max即可。gss则初始化为叶子的值即可。

la[x] = ra[x] = max(0, sum[x]); gss[x] = sum[x];

考虑如何维护la、ra、gss和sum。

再考虑如何维护upd。

upd的存储方式其实有两种:一种是把需要更新的值存储起来,另一种是修改时直接更新完毕,然后再打上bool标记。这里我采用的是后者。

下传也简单。将整个区间set成同一个值后,la、ra和gss的更新与初始化有些相似。

la和ra的代码不变,gss改成在选全部与选一个之间取max(题目要求必须选一个)。

没了?当然还有。

完整版问题

现在多了插入、删除和区间反转,维护方法相似。这里我们先考虑每个点都有权值后的变化。

其中用括号括起来的是增加的部分。

考虑同时下传反转和set两个标记。如果区间全部设置为一个值,反转也就没有意义了。所以处理顺序是set→反转。

pushdown的完整代码如下:

垃圾回收

这个毒瘤题非常恶心,卡我空间,只好写个辣鸡垃圾回收。

删除的时候,把要删除的节点全部加到一个队列里。等到要插入的时候,优先使用队列里的点。

代码很好理解。

其他用途

Splay因为其超强的区间操作能力,所以也作为LCT的辅助树使用。

Splay也可以搭配仙人掌剖分树链剖分,把一些序列上的题目出到仙人掌树上。

代码

下面附上我那常数巨大的代码,供参考用:

普通平衡树

文艺平衡树

P2042

本文发布于洛谷日报,特约作者:tiger0132

原文地址:https://tiger0132.blog.luogu.org/slay-notes

[洛谷日报第62期]Splay简易教程 (转载)的更多相关文章

  1. [洛谷日报第39期]比STL还STL?——pbds

    [洛谷日报第39期]比STL还STL?——pbds   洛谷科技 发布时间:18-08-3116:37 __gnu_pbds食用教程 引入 某P党:“你们C++的STL库真强(e)大(xin),好多数 ...

  2. [洛谷日报#204] StackEdit——Markdown 编辑器的功能介绍

    本文同时发表于洛谷日报,您也可以通过洛谷博客进行查看. 1.介绍与开始使用 1.1 这是什么? StackEdit是基于PageDown.Stack Overflow和其他堆栈交换站点使用的Markd ...

  3. 洛谷.2042.[NOI2005]维护数列(Splay)

    题目链接 2017.12.24 第一次写: 时间: 2316ms (1268ms) 空间: 19.42MB (19.5MB)(O2) 注:洛谷测的时间浮动比较大 /* 插入一段数:将这些数先单独建一棵 ...

  4. 洛谷P3391文艺平衡树(Splay)

    题目传送门 转载自https://www.cnblogs.com/yousiki/p/6147455.html,转载请注明出处 经典引文 空间效率:O(n) 时间效率:O(log n)插入.查找.删除 ...

  5. 洛谷 P4036 [JSOI2008]火星人(splay+字符串hash)

    题面 洛谷 题解 首先,我们知道求最长公共前缀可以用二分答案+hash来求 因为有修改操作, 考虑将整个字符串的hash值放入splay中 接着就是splay的基本操作了 Code #include& ...

  6. 【洛谷日报#26】GCC自带位运算系列函数

    文章转自 洛谷 谈到GCC的黑科技,大家想到的一定是这句: #pragma GCC optimize (3)//吸氧 抑或是这句: #pragma GCC diagnostic error " ...

  7. 洛谷P3391 文艺平衡树 (Splay模板)

    模板题. 注意标记即可,另外,涉及区间翻转操作,记得设立首尾哨兵. 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int ...

  8. CSP-J2020 洛谷P7072 直播获奖(Splay/桶排序)

    题目描述 NOI2130 即将举行.为了增加观赏性,CCF 决定逐一评出每个选手的成绩,并直播即时的获奖分数线.本次竞赛的获奖率为 w%,即当前排名前 w% 的选手的最低成绩就是即时的分数线. 更具体 ...

  9. 洛谷.3369.[模板]普通平衡树(Splay)

    题目链接 第一次写(2017.11.7): #include<cstdio> #include<cctype> using namespace std; const int N ...

随机推荐

  1. [USACO5.3]校园网Network of Schools

    题目描述 一些学校连入一个电脑网络.那些学校已订立了协议:每个学校都会给其它的一些学校分发软件(称作“接受学校”).注意即使 B 在 A 学校的分发列表中, A 也不一定在 B 学校的列表中. 你要写 ...

  2. [MicroPython]TPYBoard智能小车“飞奔的TPYBoard装甲一号”

    智能小车作为现代的新发明,是以后的发展方向,他可以按照预先设定的模式在一个环境里自动的运作,不需要人为的管理,可应用于科学勘探等等的用途.智能小车能够实时显示时间.速度.里程,具有自动寻迹.寻光.避障 ...

  3. face detection[SSH]

    该文来自<SSH: Single Stage Headless Face Detector>,本文时间线2017年8月. 不同于face rcnn那种两阶段的方法,SSH和ssd一样是一阶 ...

  4. CF741 D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

    题目意思很清楚了吧,那么我们从重排回文串的性质入手. 很容易得出,只要所有字符出现的次数都为偶数,或者有且只有一个字符出现为奇数就满足要求了. 然后想到什么,Hash?大可不必,可以发现字符\(\in ...

  5. 欢迎加入.NET Core 技术QQ群一起讨论交流学习

    群号:4656606 介绍:本群主要讨论.NET Core及其相关技术,如:IdentityServer4.ABP.Dcoker.Linux.Devops.微服务等,如果你正在使用或者准备使用.NET ...

  6. (通用版)salesforce中soql及sosl的伪‘Like’模糊检索

    salesforce里有soql.sosl两种查询语法,soql针对模糊搜索也有‘like’关键字,然而只能针对其自带字段如:Name.Id:对于自定义添加的字段如:Message__c.Note__ ...

  7. vue文档全局api笔记1

    全局api方法 1.Vue.extend(options) 请注意,extend创建的是一个组件构造器,而不是一个具体的组件实例.所以他不能直接在new Vue中这样使用: new Vue({comp ...

  8. 我的微信小程序第二篇

    在上一篇<我的微信小程序第一篇(入门)>中,很多人问我什么是微信小程序,在这里我要说一下这个是我的失误啦,我默认大家都知道微信小程序,其实可能行内人士都知道小程序,好多非行内朋友可能平时不 ...

  9. Python学习第三篇——逻辑判定

    request_foods=["tomato","beaf","milk"] for elements in request_foods: ...

  10. 亲测可以永久破解2018版本的pycharm

    pycharm是很强大的开发工具,但是每次注册着实让人头疼.网络上很多注册码.注册服务器等等.但都只是一年或者不能用:为次有如下解决方案.亲测有效!!! 如果想让pycharm永久被激活,比如截止日到 ...