简介:     Treap,一种表现优异的BST 优势:     其较于AVL.红黑树实现简单,浅显易懂     较于Splay常数小,通常用于树套BST表现远远优于Splay     或许有人想说SBT,SBT我没有实现过,据说比较快     但是SBT.Splay以及旋转版Treap等BST都不可以比较方便地实现‘可持久化操作   Treap=Tree+Heap     Treap是一颗同时拥有二叉搜索树和堆性质的一颗二叉树     Treap有两个关键字,在这里定义为:         1…
Treap是一种平衡二叉树,同时也是一个堆.它既具有二叉查找树的性质,也具有堆的性质.在对数据的查找.插入.删除.求第k大等操作上具有期望O(log2n)的复杂度.     Treap可以通过节点的旋转来实现其维持平衡的操作,详见旋转式Treap. 而旋转式Treap在对区间数据的操作上无能为力,这就需要非旋转式Treap来解决这些区间问题. 非旋转式Treap支持的操作 基本操作: 操作 说明 实现复杂度 Build 构造Treap O(n) Merge 合并Treap O(log2n) Sp…
在刷了许多道平衡树的题之后,对平衡树有了较为深入的理解,在这里和大家分享一下,希望对大家学习平衡树能有帮助. 平衡树有好多种,比如treap,splay,红黑树,STL中的set.在这里只介绍几种常用的:treap.splay和替罪羊树(其中treap包括旋转treap和非旋转treap). 一.treap treap这个词是由tree和heap组合而成,意思是树上的的堆(其实就是字面意思啦qwq).treap可以说是由二叉搜索树(BST)进化而来,二叉搜索树每个点满足它左子树中所有点权值都比它…
平衡树这种东西,我只会splay.splay比较好理解,并且好打,操作方便. 我以前学过SBT,但并不是很理解,所以就忘了怎么打了. 许多用平衡树的问题其实可以用线段树来解决,我们真正打平衡树的时候一般都是维护序列之类的. 维护序列时,splay特别方便,所以一般情况下打splay就好了.其它的平衡树也可以,可是如果见到翻转操作的时候,那些平衡树就会崩(至少我不知道那些平衡树有什么可以翻转的做法). 但是splay的常数很大(常数最大的平衡树),并且有的时候需要可持久化. 这个时候就要用到非旋T…
简介 二叉搜索树, 可以维护一个集合/序列, 同时维护节点的 \(size\), 因此可以支持 insert(v), delete(v), kth(p,k), rank(v)等操作. 另外, prev(v) == kth(rt,rank(v)-1); next(v) == kth(rt,rank(v)+1). 平衡树通过各种方法保证二叉搜索树的平衡, 从而达到 \(O(\log n)\) 的均摊复杂度. Splay Splay 不仅可以实现一般平衡树的操作, 还可以实现序列的翻转/旋转等操作.…
非旋  $treap$ (FHQ treap)的简单入门 前置技能 建议在掌握普通 treap 以及 左偏堆(也就是可并堆)食用本blog 原理 以随机数维护平衡,使树高期望为logn级别, FHQ 不依靠旋转,只有两个核心操作merge(合并)和split(拆分) 所谓随机数维护平衡就是给每个节点一个随机值 key (下文中没有加随机的就代表是真实权值), 然后整棵树中 key 值要满足小(大)根堆的性质(也就是heap), 同时也要满足平衡树(tree)的性质(也就是每个节点左子树内节点真实…
原文链接https://www.cnblogs.com/zhouzhendong/p/Balanced-Binary-Tree.html 注意是简单教程,不是入门教程. splay 1. 旋转: 假设点 y 原是点 x 的 father,旋转操作可以在不改变中序遍历的基础上,将 y 变成 x 的儿子.例如: 旋转后: 代码: int wson(int x){ return son[fa[x]][1]==x; } void pushup(int x){ tot[x]=cnt[x]+tot[son[…
题目: 此为平衡树系列第一道:普通平衡树您需要写一种数据结构,来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数,因输出最小的排名)4. 查询排名为x的数5. 求x的前驱(前驱定义为小于x,且最大的数)6. 求x的后继(后继定义为大于x,且最小的数) n<=100000 所有数字均在-107到107内. 输入样例: 10 1 106465 4 1 1 317721 1 460929 1 644985 1 841…
treap(树堆) 是在二叉搜索树的基础上,通过维护随机附加域,使其满足堆性质,从而使树相对平衡的二叉树: 为什么可以这样呢? 因为在维护堆的时候可以同时保证搜索树的性质: (比如当一棵树的一个域满足堆的性质时,只要不断的互换左右,她的另一个域总会满足搜索树的性质) (当一棵树的一个域满足搜索树的性质时,只要不断的上下旋转,她的另一个域总会满足二叉堆的性质) 于是树堆有两种实现: 旋转treap: 她的操作基于旋转: 注意:当存在相同val时,对于旋转treap,是存在一个节点中的: roll(…
直接上代码 正所谓 人傻自带大常数 平衡树的几种姿势:  AVL Red&Black_Tree 码量爆炸,不常用:SBT 出于各种原因,不常用. 常用: Treap 旋转 基于旋转操作和随机数堆 但不支持区间操作. 非旋转 基于随机数堆和拆分合并操作 常数较大 时间复杂度:很难被卡,均摊O(logN) #include<cstdio> #include<iostream> #include<cstdlib> #define MAXN 100005 using n…
非旋$Treap$ 其高级名字叫$Fhq\ Treap$,既然叫$Treap$,它一定满足了$Treap$的性质(虽然可能来看这篇的人一定知道$Treap$,但我还是多说几句:$Fhp\ Treap$就是继承了$Treap$的随机系统,在二叉搜索的基础上,每个点加一个随机化处理,这些随机值满足堆的性质……通俗一点讲,就是$Fhp\ Treap$它每个点有至少两个值,一个是val,即存的数值,这些数值满足二叉搜索树,也就是父亲比左孩子小/大,则右孩子比父亲小/大:还有一个是key,是个随机值,这些…
非旋转Treap:用运行时间换调试时间的有效手段   Hello大家好,我们今天来聊一聊非旋转Treap. 相信各位或多或少都做过些序列上的问题.如果水题我们考虑暴力:不强制在线我们可能用过莫队和待修改莫队:不更改序列上的时间戳信息的我们使用线段树或者树状数组,也有可能请出主席树.那如果更大幅度的操作,我们要用到splay或者块链.但是!我们今天介绍一种特殊的平衡树,用时间换取时间的数据结构. 啥意思?如果写过splay和块链,前者的调试时间和后者的敲版子时间让我们头痛欲裂,但是这个平衡树,好写…
bzoj3580 非旋转treap 在大神教导下发现split一段区间时先split右边再split左边比较好写 #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cmath> #include <cctype> using namespace std; typedef long long LL; const i…
最长上升子序列 bzoj-3173 题目大意:有1-n,n个数,第i次操作是将i加入到原有序列中制定的位置,后查询当前序列中最长上升子序列长度. 注释:1<=n<=10,000,开始序列为空. 想法:显然,我们发现,我每次加入的数一定是当前序列中最大的,所以,刚刚加入的i,要么是当前序列中LIS的结尾,要么不属于LIS.根据这个性质,我们想到:在Treap中维护这样的性质,就是维护每个数加入节点的编号.然后,我们更新新节点的方式就是它的左子树和右子树的LIS取最大+1.其实最重要的就是如何加入…
非旋转treap的操作基于split和merge操作,其余操作和普通平衡树一样,复杂度保证方式与旋转treap差不多,都是基于一个随机的参数,这样构出的树树高为\(logn\) split 作用:将原平衡树分为排名为\([1,k]\),\([k+1,n]\)的两棵平衡树 实现: 1.如果\(x\)左儿子的子树大小\(size[l]==k\),那么\(x\)左儿子即为\([1,k]\)这个平衡树的根,\(x\)本身为另一颗平衡树的根 2.如果\(x\)左儿子的子树大小\(size[l]+1==k\…
题目链接: Codeforces702F 题目大意:有$n$种T恤,每种有一个价格$c_{i}$和品质$q_{i}$且每种数量无限.现在有$m$个人,第$i$个人有$v_{i}$元,每人每次会买他能买得起的品质最高的一件T恤(当两件T恤品质相同时优先买价格低的),每人只能买一件每种T恤.求最后每个人买的T恤件数. 暴力的方法是将T恤品质从大到小排序,对于每个人从第一种T恤(排序后的第一种)开始模拟每件T恤,能买就买,不能买就跳过. 发现暴力的方法是对于每个人决策每件T恤,我们可以对于每件T恤来决…
题目描述 小奇成功打开了大科学家的电脑. 大科学家打算前往n处景点旅游,他用一个序列来维护它们之间的顺序.初 始时,序列为1,2,...,n. 接着,大科学家进行m次操作来打乱顺序.每次操作有6步: 1.从序列开头(左端)取出A个数(此时序列剩下n-A个数) 2.从序列开头取出B个数 3.将第1步取出的A个数按原顺序放回序列开头 4.从序列开头取出C个数 5.将第2步取出的B个数逆序放回序列开头 6.将第4步取出的C个数按原顺序放回序列开头 你需要求出最终序列. 输入 第一行两个数n,m.接下来…
此为平衡树系列第二道:文艺平衡树您需要写一种数据结构,来维护一个有序数列,其中需要提供以下操作: 翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 输入 第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n) m表示翻转操作次数接下来m行每行两个数[l,r] 数据保证 1<=l<=r<=n 输出 输出一行n个数字,表示原始序列经过m次变换后的结果 样例输入 5 3 1 3 1 3 1 4 样例输出 4 3 2 1…
Sylvia 是一个热爱学习的女孩子.  前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia所在的方阵中有n × m名学生,方阵的行数为 n,列数为m.  为了便于管理,教官在训练开始时,按照从前到后,从左到右的顺序给方阵中的学生从 1 到 n × m 编上了号码(参见后面的样例).即:初始时,第 i 行第 j 列的学生的编号是(i − 1) × m + j.  然而在练习方阵的时候,经常会有学生因为各种各样的事情需要离队.在一天中,一共发生了 q 件这样的…
题目描述 某一天gty在与他的妹子玩游戏.妹子提出一个游戏,给定一棵有根树,每个节点有一些石子,每次可以将不多于L的石子移动到父节点,询问将某个节点的子树中的石子移动到这个节点先手是否有必胜策略.gty很快计算出了策略.但gty的妹子十分机智,她决定修改某个节点的石子或加入某个新节点.gty不忍心打击妹子,所以他将这个问题交给了你.另外由于gty十分绅士,所以他将先手让给了妹子. 输入 第一行两个数字,n和L,n<=5*10^4,L<=10^9第二行n个数字,表示每个节点初始石子数.接下来n-…
题目描述 输入 输入共两行,第一行为一个整数N,N表示物品的个数,1<=N<=100000. 第二行为N个用空格隔开的正整数,表示N个物品最初排列的编号. 输出 输出共一行,N个用空格隔开的正整数P1,P2,P3…Pn,Pi表示第i次操作前第i小的物品所在的位置.  注意:如果第i次操作前,第i小的物品己经在正确的位置Pi上,我们将区间[Pi,Pi]反转(单个物品). 样例输入 6 3 4 5 1 6 2 样例输出 4 6 4 5 6 6   非旋转treap练习题.题目要求每次找到第i小的P…
题目描述 网上有许多题,就是给定一个序列,要你支持几种操作:A.B.C.D.一看另一道题,又是一个序列 要支持几种操作:D.C.B.A.尤其是我们这里的某人,出模拟试题,居然还出了一道这样的,真是没技术含量……这样 我也出一道题,我出这一道的目的是为了让大家以后做这种题目有一个“库”可以依靠,没有什么其他的意思.这道题目 就叫序列终结者吧. [问题描述] 给定一个长度为N的序列,每个序列的元素是一个整数(废话).要支持以下三种操作: 1. 将[L,R]这个区间内的所有数加上V. 2. 将[L,R…
题目描述 请写一个程序,要求维护一个数列,支持以下 6 种操作: 请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格 输入 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格.任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内.插入的数字总数不超过4 000 000个,输入文件大小不超过20MBy…
国际惯例的题面:看起来很不可做的样子,我们先来整理一下题意吧.就是,维护每个点曾经拥有过的最大的两个属性值,支持把点的位置移动.我们用map对每个位置进行离散化,对每个位置建立一个平衡树.为了方便分离,这个平衡树的关键字是节点编号.然后把每个点当做一个节点,放进其所在位置的平衡树里.剩下要做的就是平衡树分离出一个点,合并一个点,还有打标记了.对于士气值的标记,我们维护平衡树中的max,每次合并的时候,用这个新点的威武值去给整棵树打标记,再用树中的max给这个新点打标记.团结值的标记,合并后一起打…
国际惯例的题面:这种维护排序序列,严格大于的进行操作的题都很套路......我们按照[0,k],(k,2k],(2k,inf)分类讨论一下就好.显然第一个区间的不会变化,第二个区间的会被平移进第一个区间,第三个区间的相对大小不会变化.于是我们直接把第二个区间拆了重构,一个一个插入第一个区间即可.因为每次这样做最少减半,所以每个元素只会被重构log次,复杂度nlog^2n.这种按照值域分离区间的操作,非旋转treap实现起来是最简单的......然而第一次写非旋转treap还是出了一点问题,注意它…
描述 有N张卡片,编号从0到n-1, 刚开始从0到n-1按顺序排好. 现有一个操作, 对于p. l,表示从第p张卡片之后的l张卡片拿到 最前面. 例如n=7的时候, 刚开始卡片序列为0 1 2 3 4 5 6 对于操作p=2 l=3执行一次之后序列变为 2 3 4 0 1 5 6 求出所有操作之后, 奇数位上编号的和 输入 第一行两个整数 N. M,表示有 N 张卡片,接下来 M 个操作. 接下来 M 行, 每行有三个整数 p. l. r, 表示重复 r 次 p. l 操作. 输出 一个整数表示…
描述 初始有一个空集,依次插入N个数Ai.有M次询问Bj,表示询问第Bj个数加入集合后的排名为j的数是多少 输入 第一行是两个整数N,M 接下来一行有N个整数,Ai 接下来一行有M个整数Bj,保证数据合法 输出 M行,回答每个询问 样例输入 7 4 9 7 2 8 14 1 8 1 2 6 6 样例输出 9 9 7 8 提示 [说明] 第一次询问,当前集合{9},1th=9 第二次询问,当前集合{9,7}的第2=9 第三次询问,当前集合{9,7,2,8,14,1}的第3=7 第四次询问,当前集合…
传送门 平衡树好题. 我仍然是用的fhqtreap,感觉速度还行. 维护也比线段树splay什么的写起来简单. %%%非旋treap大法好. 代码: #include<bits/stdc++.h> #define N 500005 #define inf 0x3f3f3f3f using namespace std; queue<int>garbage; typedef pair<int,int> res; int n,m,rt=0,cnt=0,a[N],son[N][…
传送门 经典的平衡树问题,之前已经用splay写过一次了,今天我突发奇想,写了一发非旋treap的版本,发现挺好写的(虽然跑不过splay). 代码: #include<bits/stdc++.h> #define N 100005 using namespace std; typedef pair<int,int> res; int rt=0,n,m,cnt=0,son[N][2],siz[N],val[N],rd[N],rev[N]; inline int read(){ in…
传送门 就是普通平衡树,可以拿来练非旋treap" role="presentation" style="position: relative;">treaptreap的板子. 贴个代码: #include<bits/stdc++.h> #define N 300005 using namespace std; typedef pair<int,int> res; int n; inline int read(){ int a…