关于非旋转treap的学习
非旋转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\),那么\(x\)为\([1,k]\)这个平衡树的根,\(x\)右儿子为另一颗平衡树的根
3.如果是上述情况,直接把左儿子或右儿子接上去就好
4.否则,递归处理,直到出现这两种情况位置
inline void split(int x,int k,int &a,int &b){
if(!k){a=0;b=x;return ;}
int l=ch[x][0],r=ch[x][1];
if(sz[l]==k)ch[x][0]=0,a=l,b=x;
else if(sz[l]+1==k)ch[x][1]=0,a=x,b=r;
else if(sz[l]>k)split(l,k,a,ch[x][0]),b=x;
else split(r,k-sz[l]-1,ch[x][1],b),a=x;
upd(x);
}
merge
作用:将两棵平衡树合并,合并后参数满足\(heap\)的性质,且满足平衡树性质.
实现:
我们强制\(merge(x,y)\)中\(x\)的所有节点的关键字都小于所有\(y\)的关键字,根据关键字合并即可.
inline int merge(int x,int y){
if(!x||!y)return x+y;
if(key[x]>key[y]){
ch[x][1]=merge(ch[x][1],y);
upd(x);
return x;
}
else{
ch[y][0]=merge(x,ch[y][0]);
upd(y);
return y;
}
}
insert
以\(x\)的前驱为界,拆原树为两棵树,将左树合并到\(x\),再将\(x\)合并到右树
inline void ins(int x){
v[++cnt]=x;key[cnt]=rand();sz[cnt]=1;
int l,r;
split(rt,rank(x)-1,l,r);
rt=merge(merge(l,cnt),r);
}
delet
以\(x\)为界\(split\)原树,删除\(x\)后再合并左右子树
inline void Delet(int x){
int l,r;
split(rt,x,l,r);
split(l,x-1,l,x);
rt=merge(l,r);
}
标记下放
只需在\(merge\),\(split\),\(kth\),\(rank\)函数前下放即可
完整代码:
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const int N=100005;
int ch[N][2],sz[N],key[N],cnt=0,v[N],rt;
inline void upd(int x){sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;}
inline void split(int x,int k,int &a,int &b){
if(!k){a=0;b=x;return ;}
int l=ch[x][0],r=ch[x][1];
if(sz[l]==k)ch[x][0]=0,a=l,b=x;
else if(sz[l]+1==k)ch[x][1]=0,a=x,b=r;
else if(sz[l]>k)split(l,k,a,ch[x][0]),b=x;
else split(r,k-sz[l]-1,ch[x][1],b),a=x;
upd(x);
}
inline int merge(int x,int y){
if(!x||!y)return x+y;
if(key[x]>key[y]){
ch[x][1]=merge(ch[x][1],y);
upd(x);
return x;
}
else{
ch[y][0]=merge(x,ch[y][0]);
upd(y);
return y;
}
}
inline int rank(int k){
int x=rt,ret=1;
while(x){
if(k<=v[x])x=ch[x][0];
else ret+=sz[ch[x][0]]+1,x=ch[x][1];
}
return ret;
}
inline int kth(int k){
int x=rt,sum;
while(x){
sum=sz[ch[x][0]];
if(sum==k-1)return v[x];
if(sum>=k)x=ch[x][0];
else x=ch[x][1],k-=sum+1;
}return 0;
}
inline void ins(int x){
v[++cnt]=x;key[cnt]=rand();sz[cnt]=1;
int l,r;
split(rt,rank(x)-1,l,r);
rt=merge(merge(l,cnt),r);
}
inline void Delet(int x){
int l,r;
split(rt,x,l,r);
split(l,x-1,l,x);
rt=merge(l,r);
}
void work()
{
int n,op,x;
scanf("%d",&n);
while(n--){
scanf("%d%d",&op,&x);
if(op==1)ins(x);
else if(op==2)Delet(rank(x));
else if(op==3)printf("%d\n",rank(x));
else if(op==4)printf("%d\n",kth(x));
else if(op==5)printf("%d\n",kth(rank(x)-1));
else if(op==6)printf("%d\n",kth(rank(x+1)));
}
}
int main()
{
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
work();
return 0;
}
关于非旋转treap的学习的更多相关文章
- 左偏树 / 非旋转treap学习笔记
背景 非旋转treap真的好久没有用过了... 左偏树由于之前学的时候没有写学习笔记, 学得也并不牢固. 所以打算写这么一篇学习笔记, 讲讲左偏树和非旋转treap. 左偏树 定义 左偏树(Lefti ...
- [NOIP]2017列队——旋转treap/非旋转treap
Sylvia 是一个热爱学习的女孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia所在的方阵中有n × m名学生,方阵的行数为 n,列数为m. 为了便 ...
- 平衡树及笛卡尔树讲解(旋转treap,非旋转treap,splay,替罪羊树及可持久化)
在刷了许多道平衡树的题之后,对平衡树有了较为深入的理解,在这里和大家分享一下,希望对大家学习平衡树能有帮助. 平衡树有好多种,比如treap,splay,红黑树,STL中的set.在这里只介绍几种常用 ...
- [bzoj3173]最长上升子序列_非旋转Treap
最长上升子序列 bzoj-3173 题目大意:有1-n,n个数,第i次操作是将i加入到原有序列中制定的位置,后查询当前序列中最长上升子序列长度. 注释:1<=n<=10,000,开始序列为 ...
- [Codeforces702F]T-Shirts——非旋转treap+贪心
题目链接: Codeforces702F 题目大意:有$n$种T恤,每种有一个价格$c_{i}$和品质$q_{i}$且每种数量无限.现在有$m$个人,第$i$个人有$v_{i}$元,每人每次会买他能买 ...
- BZOJ5063旅游——非旋转treap
题目描述 小奇成功打开了大科学家的电脑. 大科学家打算前往n处景点旅游,他用一个序列来维护它们之间的顺序.初 始时,序列为1,2,...,n. 接着,大科学家进行m次操作来打乱顺序.每次操作有6步: ...
- BZOJ3223文艺平衡树——非旋转treap
此为平衡树系列第二道:文艺平衡树您需要写一种数据结构,来维护一个有序数列,其中需要提供以下操作: 翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 ...
- BZOJ3224普通平衡树——非旋转treap
题目: 此为平衡树系列第一道:普通平衡树您需要写一种数据结构,来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数, ...
- BZOJ3729Gty的游戏——阶梯博弈+巴什博弈+非旋转treap(平衡树动态维护dfs序)
题目描述 某一天gty在与他的妹子玩游戏.妹子提出一个游戏,给定一棵有根树,每个节点有一些石子,每次可以将不多于L的石子移动到父节点,询问将某个节点的子树中的石子移动到这个节点先手是否有必胜策略.gt ...
随机推荐
- JAVA对象克隆
1> 为了获取对象的一份拷贝,我们可以利用Object类的clone()方法. 2> 在派生类中覆盖基类的clone(),并声明为public.3> 在派生类的clone()方法中, ...
- Flask 学习 五 电子邮件
pip install mail from flask_mail import Mail # 邮件配置 app.config['MAIL_SERVER']='smtp.qq.com' app.conf ...
- 坑爹了多少年的html元素垂直居中问题
原文章:https://www.w3cplus.com/css3/a-guide-to-flexbox.html 如果你的元素有固定高度的话 父元素用display: flex;height:100p ...
- JAVA_SE基础——66.StringBuffer类 ③
如果需要频繁修改字符串 的内容,建议使用字符串缓冲 类(StringBuffer). StringBuffer 其实就是一个存储字符 的容器. 容器的具备 的行为 常用方法 String 增加 ap ...
- 构建自己的 PHP 框架
这是一个系列的文章,项目地址在这里,欢迎大家star. 这个框架前一部分比较像Yii,后一部分比较像Laravel,因为当时正在看相应框架的源码,所以会有不少借鉴参考.捂脸- 这个框架千万不要直接应用 ...
- js window
window对象: browser object mode :bom对象. bom提供了独立于内容而与浏览器窗口进行交互的对象. bom主要用于管理窗口与窗口之间的通讯,因此其核心对象是window ...
- 在Vim按了ctrl+s后
在windows我们码代码的时候习惯ctrl+s保存: 但在vim中使用ctrl+s之后终端就没反应了... vim: ctrl+s终止屏幕输出,敲的东西都有效,就是看不见. ctrl+q恢复:
- Class-Based-View(CBV)
我们都知道,Python是一个面向对象的编程语言,如果只用函数来开发,有很多面向对象的优点就错失了(继承.封装.多态).所以Django在后来加入了Class-Based-View.可以让我们用类写V ...
- Hey,man,are you ok? -- 关于心跳、故障监测、lease机制
电话之于短信.微信的一个很大的不同点在于,前者更加及时,有更快速直接的反馈:而后面两个虽然称之为instant message,但经常时发出去了就得等对方回复,等多久是不确定的.打电话能明确知道对方在 ...
- ( 转 ) 聊一聊C#的Equals()和GetHashCode()方法
聊一聊C#的Equals()和GetHashCode()方法 博客创建一年多,还是第一次写博文,有什么不对的地方还请多多指教. 关于这次写的内容可以说是老生长谈,百度一搜一大堆.大神可自行绕路. ...