splay

文艺平衡Splay树学习笔记(2)

谁都会走 提交于 2019-12-30 05:43:03
本blog会讲一些简单的Splay的应用,包括但不局限于 1. Splay 维护数组下标,支持区间reserve操作,解决区间问题 2. Splay 的启发式合并(按元素多少合并) 3. 线段树+Splay 大常数树套树 一、Splay维护区间下标解决区间翻转问题 思想: 对于数组的下标是不可重复的,我们使用平衡树维护下标,利用Splay的splay操作,让区间都在一棵子树内。 然后直接输出这颗子树的维护信息,由于维护的是子树信息,那么父亲的信息一定可以由两个儿子推出。 于是就可以类似于线段树的操作了(用儿子信息维护父亲信息)。 [LuoGu 模板] 文艺平衡树 : 维护区间翻转,输出最终区间形态。 Solution : 考虑splay函数的实质,就是把节点x转到目标节点,并且让Splay树保持BST的性质。 那么显然,对于维护序列下标,其维护的值便是元素对于数组的位置。(一个节点左边儿子子树的位置都小于该节点) 对于一个区间进行翻转,那么事实上就是 把l和r下标交换,l+1和r-1下标交换... 那么如何确定这个区间呢,不妨把[l-1]转到根节点,[r+1]转到根节点的右儿子,那么对于根节点右儿子的左儿子所在子树 就可以描述为[l,r]区间。 然而,对于Splay本身来说是不能出现下标为0的情况的,否则会死循环,在(1)中已经讲的非常明确了,所以我们仍然加入一个哨兵节点

绝对是全网最好的Splay 入门详解——洛谷P3369&BZOJ3224: Tyvj 1728 普通平衡树 包教包会

一曲冷凌霜 提交于 2019-12-26 18:55:42
平衡树 是什么东西想必我就不用说太多了吧。 百度百科 : 一个月之前的某天晚上,yuli巨佬为我们初步讲解了Splay,当时接触到了平衡树里的旋转等各种骚操作,感觉非常厉害。 而第二天我调Splay的模板竟然就搞了一天,最后还是失败告终,只能CV了事,而Splay也成了我心中的一个心结,一直没法解决。 在西安集训的时候也没有去自己亲自地把Splay调出来AC,后来又面临期末考试,直到今天,我再一次地尝试将Splay调出来,又 花了2个多小时的时间。这个过程是非常痛苦的,翻了无数篇博客,看了无数题解,我才勉强打出了适合我自己的Splay模板。   看到 AC 的那一瞬间,心里面是五味杂陈,虽然我是如此垃圾,现在我才自己将这样的模板A掉,但看了网上那么多篇博客,学了很多种方法,但适合 我自己的我却花了很长的时间才完成。所以我希望写一篇博客,真真正正地手把手教大家Splay(仅仅是模板),让学Splay的神犇们少走一些弯路。 这也许就是我这一篇博客的意义所在吧。 来看洛谷的题面: 基本操作简介: 维护的数组: size[]:子树的大小 cnt[]:某个节点出现的次数 fa[]:某个节点它的父亲节点 val[]:某个节点对应的权值 lc[]:该节点的左儿子 rc[]:该节点的右儿子 变量: root 根 tot 统计节点数 函数: clear:用于删除节点时的清空 代码如下: push

Link-Cut-Tree详解

久未见 提交于 2019-12-26 05:32:40
图片参考 YangZhe的论文 , FlashHu大佬的博客 Link-Cut-Tree实际靠的是实链剖分,重链剖分和长链剖分珂以参考 树链剖分详解 Link-Cut-Tree将某一个儿子的连边划分为实边,而连向其他子树的边划分为虚边 区别在于虚实是可以动态变化的,因此要使用更高级、更灵活的Splay来维护每一条由若干实边连接而成的实链 请先学习 Splay 之后再阅读本文 Link-Cut-Tree功能强大,能维护以下东西: 查询、修改链上的信息(最值,总和等) 随意指定原树的根(即换根) 动态连边、删边 动态维护连通性 更多毒瘤操作 Link-Cut-Tree的性质 1.每一个Splay维护的是一条从上到下按在原树中深度严格递增的路径,且中序遍历Splay得到的每个点的深度序列严格递增 2.每个节点包含且仅包含于一个Splay中 3.边分为实边和虚边,实边包含在Splay中,而虚边总是由一棵Splay指向另一个节点(指向该Splay中中序遍历最靠前的点在原树中的父亲) 因为性质2,当某点在原树中有多个儿子时,只能向其中一个儿子拉一条实链(只认一个儿子),而其它儿子是不能在这个Splay中的 那么为了保持树的形状,我们要让到其它儿子的边变为虚边,由对应儿子所属的Splay的根节点的父亲指向该点,而从该点并不能直接访问该儿子(认父不认子) 核心操作(以下代码以 Luogu

LCT学习笔记

大兔子大兔子 提交于 2019-12-23 22:55:09
最近自学了一下LCT(Link-Cut-Tree),参考了Saramanda及Yang_Zhe等众多大神的论文博客,对LCT有了一个初步的认识,LCT是一种动态树,可以处理动态问题的算法。对于树分治中的树链剖分,只能处理静态的数据或者在轻重链上的边或点的权值,对于其他动态的处理就毫无办法了。因此我们就需要引入LCT这个东西。那么问题来了,LCT到底是什么呢?我弄了很久总算是理解了LCT,打算总结一下LCT的基本操作。 ①浅谈对LCT的初步印象 LCT用来维护动态的森林,以及一些链上操作 , 是处理节点无序的有根树组成的森林,进行一些列操作(例如合并,剪切,翻转,更新·····) 对于一棵树的操作,我们可以用splay维护;同理,对于一片森林,也可以用多棵splay维护,而LCT就是要把这些森林的splay联系在一起。 而LCT的核心就是access操作啦! 看完之后我们知道,LCT和静态的树链剖分很像。怎么说呢?这两种树形结构都是由若干条长度不等的“重链”和“轻边”构成(名字可以不同,大概就是这个意思),“重链”之间由”轻边”连接。就像这样: 可以想象为一棵树被人为的砍成了一段段。   LCT和树链剖分不同的是,树链剖分的链是不会变化的,所以可以很方便的用线段树维护。但是,既然是动态树,那么树的结构形态将会发生改变,所以我们要用更加灵活的维护区间的结构来对链进行维护

平衡树之Splay

烈酒焚心 提交于 2019-12-21 22:17:22
算法简介 Splay是一种平衡树,支持插入、删除、求排名、求第 \(k\) 大数、求前驱和求后继的操作,并且它还能做到一般平衡树做不到的区间操作。 定义与性质 先说二叉查找树:就是把所有数建在树上,且左边的数永远小于右边的。 对于上面说的那6个操作,其实在数据随机时二叉查找树时最强的,但是数据一条链你就Good Game了。 这种情况我们希望这棵二叉查找树的节点深度差不要太大,这就有了平衡树。 顾名思义,平衡树是平衡的二叉查找树,意思就是说1条链这种数据对于平衡树来说完全不存在,这样复杂度就有保证了。 基础操作 核心操作 这些都是很重要的操作,直接维护了Splay的平衡。 pushup 维护子树大小,很简单,不谈。好像只在旋转操作中出现。 inline void pushup(int x) { siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+ct[x]; } 左右旋 核心中的核心,是另外一个核心操作的基础核心操作。 这个东西可以改变两个相邻节点的父子关系,并且仍然满足平衡树的性质。给张图,就可以看明白了。 inline void rota(int x) { int y=ff[x],z=ff[y],k=(x==ch[y][1]); ch[z][y==ch[z][1]]=x; ff[x]=z; ch[y][k]=ch[x][k^1]; ff[ch[x][k^1]]

平衡树之splay讲解

别说谁变了你拦得住时间么 提交于 2019-12-17 01:01:17
  首先来说是splay是二叉搜索树,它可以说是线段树和SBT的综合,更可以解决一些二者解决不了的问题,splay几乎所有的操作都是由splay这一操作完成的,在介绍这一操作前我们先介绍几个概念和定义   二叉搜索树,即BST(binary search tree),这样的树有一个关键字,满足对于每个节点来说,以该节点左儿子为根节点的子树中的所有节点的关键字小于该节点的关键字,以该节点右儿子为根节点的子树中的所有节点的关键字大于该节点的关键字。   splay主要可以用来解决区间的维护问题   假设我们需要维护一个数列,支持   1.在数列第i位后插入一个长为l的数列   2.在数列第i为后删除一个长为l的数列    3.将数列的l r区间翻转(1 2 3 2 3 翻转后为 3 2 3 2 1)   4.将数列的l r区间同时加上一个值   5.将数列的l r区间同时改为一个值   6.求数列的l r区间的和(最大值)   其实线段树上的大部分操作这里都支持,比如区间最大子区间和   首先对于当前的树,它的中序遍历就是当前的区间,每个点的关键字(二叉搜索树的那个)是内个点表示区间元素的标号,比如一个点的关键字是3,那么这个点代表区间中第3个元素,每个点除了关键字外还记录了一个tree[i]代表这个点对应区间内的元素是什么。   上图(节点内的数代表tree值)的树表示数列 3 7

BZOJ3506: [Cqoi2014]排序机械臂

≯℡__Kan透↙ 提交于 2019-12-16 21:04:59
BZOJ3506: [Cqoi2014]排序机械臂 额,$BZOJ$上没有题面。。。 本蒟蒻表示没钱氪金。。。 这里附上洛谷的题面: 洛谷P3165 [CQOI2014]排序机械臂 题目描述 为了把工厂中高低不等的物品按从低到高排好序,工程师发明了一种排序机械臂。 它遵循一个简单的排序规则,第一次操作找到高度最低的物品的位置 $ P_1$ ​ ,并把左起第一个物品至 $ P_1$ ​ 间的物品 (即区间 $ [1,P_1]$ 间的物品) 反序;第二次找到第二低的物品的位置 $ P_2$ ​ ,并把左起第二个至 $ P_2$ ​ 间的物品 (即区间 $ [2,P_2]$ 间的物品) 反序……最终所有的物品都会被排好序。 上图给出有六个物品的示例,第一次操作前,高度最低的物品在位置 $ 4 $ ,于是把第一至第四的物品反序;第二次操作前,第二低的物品在位罝六,于是把第二至六的物品反序…… 你的任务便是编写一个程序,确定一个操作序列,即每次操作前第$ i $ 低的物品所在位置$ P_i$ ,以便机械臂工作。 需要注意的是,如果有高度相同的物品,必须保证排序后它们的相对位置关系与初始时相同。 输入输出格式 输入格式: 第一行包含正整数n,表示需要排序的物品数星。 第二行包含n个空格分隔的整数$ P_i$ ,表示每个物品的高度。 输出格式: 输出一行包含n个空格分隔的整数Pi。 输入输出样例

[HNOI2004]宠物收养场

心已入冬 提交于 2019-12-15 06:58:07
题目描述 凡凡开了一间宠物收养场。收养场提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物。 每个领养者都希望领养到自己满意的宠物,凡凡根据领养者的要求通过他自己发明的一个特殊的公式,得出该领养者希望领养的宠物的特点值a(a是一个正整数,a<2^31),而他也给每个处在收养场的宠物一个特点值。这样他就能够很方便的处理整个领养宠物的过程了,宠物收养场总是会有两种情况发生:被遗弃的宠物过多或者是想要收养宠物的人太多,而宠物太少。 被遗弃的宠物过多时,假若到来一个领养者,这个领养者希望领养的宠物的特点值为a,那么它将会领养一只目前未被领养的宠物中特点值最接近a的一只宠物。(任何两只宠物的特点值都不可能是相同的,任何两个领养者的希望领养宠物的特点值也不可能是一样的)如果有两只满足要求的宠物,即存在两只宠物他们的特点值分别为a-b和a+b,那么领养者将会领养特点值为a-b的那只宠物。 收养宠物的人过多,假若到来一只被收养的宠物,那么哪个领养者能够领养它呢?能够领养它的领养者,是那个希望被领养宠物的特点值最接近该宠物特点值的领养者,如果该宠物的特点值为a,存在两个领养者他们希望领养宠物的特点值分别为a-b和a+b,那么特点值为a-b的那个领养者将成功领养该宠物。 一个领养者领养了一个特点值为a的宠物,而它本身希望领养的宠物的特点值为b,那么这个领养者的不满意程度为abs(a-b)。

Splay

ⅰ亾dé卋堺 提交于 2019-12-14 02:37:17
本文参考资料: From yyb: Link 正文:关于SPLAY 其实我更偏向于把splay叫做 cosplay 讲平衡树总逃不过BST(Binary Search Tree),二叉搜索树,以下是BST的性质: 一棵合法的BST每个节点上都带有一个数值,我们将其称为节点的“关键码”。那么对于一棵BST上的任意节点,满足: 该节点的关键码不小于它左子树的任意结点的关键码 该结点的关键码不大于它右子树的任意结点的关键码 显然 ,BST的中序遍历是一个递增的序列 建立一棵BST 因为笔者很懒,不想到处判边界,所以我们一般可以在一棵空的BST中预先插入两个结点,一个正无穷,一个负无穷,如图: const int SIZE = 1e5 + 5 ; const int INF = 0x7fffffff ; struct BSTNode { int l , r ; // 左右儿子的编号 int val ; // 关键码 } T [ SIZE ] ; int tot , root ; int clone ( int val ) { // 新建节点 T [ ++ tot ] . val = val ; return tot ; } void build ( ) { clone ( - INF ) , clone ( INF ) ; root = 1 , T [ 1 ] . r = 2 ; }

BZOJ 1208: [HNOI2004]宠物收养所(Splay)

我是研究僧i 提交于 2019-12-12 03:11:42
题目描述 最近,阿Q开了一间宠物收养所。收养所提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物。每个领养者都希望领养到自己满意的宠物,阿Q根据领养者的要求通过他自己发明的一个特殊的公式,得出该领养者希望领养的宠物的特点值a(a是一个正整数,a<2^31),而他也给每个处在收养所的宠物一个特点值。这样他就能够很方便的处理整个领养宠物的过程了,宠物收养所总是会有两种情况发生:被遗弃的宠物过多或者是想要收养宠物的人太多,而宠物太少。 1. 被遗弃的宠物过多时,假若到来一个领养者,这个领养者希望领养的宠物的特点值为a,那么它将会领养一只目前未被领养的宠物中特点值最接近a的一只宠物。(任何两只宠物的特点值都不可能是相同的,任何两个领养者的希望领养宠物的特点值也不可能是一样的)如果有两只满足要求的宠物,即存在两只宠物他们的特点值分别为a-b和a+b,那么领养者将会领养特点值为a-b的那只宠物。 2. 收养宠物的人过多,假若到来一只被收养的宠物,那么哪个领养者能够领养它呢?能够领养它的领养者,是那个希望被领养宠物的特点值最接近该宠物特点值的领养者,如果该宠物的特点值为a,存在两个领养者他们希望领养宠物的特点值分别为a-b和a+b,那么特点值为a-b的那个领养者将成功领养该宠物。 一个领养者领养了一个特点值为a的宠物,而它本身希望领养的宠物的特点值为b,那么这个领养者的不满意程度为abs