BZOJ3224普通平衡树——非旋转treap
题目:
此为平衡树系列第一道:普通平衡树您需要写一种数据结构,来维护一些数,其中需要提供以下操作:
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 84185
1 89851
6 81968
1 492737
5 493598
106465
84185
492737
变量声明:size[x],以x为根节点的子树大小;ls[x],x的左儿子;rs[x],x的右子树;r[x],x节点的随机数;v[x],x节点的权值。
root,树的总根;tot,树的大小。
非旋转treap不同于旋转treap需要靠旋转来维护平衡树的性质,他的操作可以用简单暴力来形容——只有合并和断裂两个操作。他不但有treap的优良性质,还有许多优点:支持可持久化和区间操作,常数比splay小。
下面介绍一下非旋转treap的这两个操作:
1.断裂
就是去掉一条边,把treap拆分成两棵树,对于区间操作可以进行两次断裂来分割出一段区间再进行操作。
以查找value为例,从root往下走,如果v[x]>value,那么下一步走ls[x],之后的点都比x小,把x接到右树上,下一次再接到右树上的点就是x的左儿子。
v[x]<=value与上述类似,在这里不加赘述。
void split(int x,int &lroot,int &rroot,int val)
{
if(!x)
{
lroot=rroot=0;
return ;
}
if(v[x]<=val)
{
lroot=x;
split(rs[x],rs[lroot],rroot,val);
}
else
{
rroot=x;
split(ls[x],lroot,ls[rroot],val);
}
up(x);
}
2.合并
就是把断裂开的树合并起来,因为要维护堆的性质所以按可并堆来合并。
void merge(int &x,int a,int b)
{
if(!a||!b)
{
x=a+b;
return ;
}
if(r[a]<r[b])
{
x=a;
merge(rs[x],rs[a],b);
}
else
{
x=b;
merge(ls[x],a,ls[b]);
}
up(x);
}
为了方便删除,所以建议把相同权值的点分开来加入树中,不要都放在同一个点。
非旋转treap代码比较短(为了清晰我写的比较长qwq)。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;
int INF=1000000000;
int n;
int opt,x;
int r[100010];
int ls[100010];
int rs[100010];
int size[100010];
int v[100010];
int root;
int tot;
void up(int x)
{
size[x]=size[ls[x]]+size[rs[x]]+1;
}
void build(int &x,int val)
{
tot++;
size[tot]=1;
r[tot]=rand();
v[tot]=val;
ls[tot]=rs[tot]=0;
x=tot;
}
void merge(int &x,int a,int b)
{
if(!a||!b)
{
x=a+b;
return ;
}
if(r[a]<r[b])
{
x=a;
merge(rs[x],rs[a],b);
}
else
{
x=b;
merge(ls[x],a,ls[b]);
}
up(x);
}
void split(int x,int &lroot,int &rroot,int val)
{
if(!x)
{
lroot=rroot=0;
return ;
}
if(v[x]<=val)
{
lroot=x;
split(rs[x],rs[lroot],rroot,val);
}
else
{
rroot=x;
split(ls[x],lroot,ls[rroot],val);
}
up(x);
}
void insert_sum(int val)
{
int x=0;
int y=0;
int z=0;
build(z,val);
split(root,x,y,val);
merge(x,x,z);
merge(root,x,y);
}
void delete_sum(int val)
{
int x=0;
int y=0;
int z=0;
split(root,x,y,val);
split(x,x,z,val-1);
merge(z,ls[z],rs[z]);
merge(x,x,z);
merge(root,x,y);
}
void ask_rank(int val)
{
int x=0;
int y=0;
split(root,x,y,val-1);
printf("%d\n",size[x]+1);
merge(root,x,y);
}
void ask_sum(int x,int num)
{
while(size[ls[x]]+1!=num)
{
if(num<=size[ls[x]])
{
x=ls[x];
}
else
{
num-=(size[ls[x]]+1);
x=rs[x];
}
}
printf("%d\n",v[x]);
}
void ask_front(int val)
{
int x=0;
int y=0;
split(root,x,y,val-1);
if(size[x]==0)
{
printf("0\n");
}
else
{
ask_sum(x,size[x]);
}
merge(root,x,y);
}
void ask_back(int val)
{
int x=0;
int y=0;
split(root,x,y,val);
ask_sum(y,1);
merge(root,x,y);
}
int main()
{
srand(16);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&opt,&x);
if(opt==1)
{
insert_sum(x);
}
else if(opt==2)
{
delete_sum(x);
}
else if(opt==3)
{
if(tot==0)
{
printf("0\n");
}
else
{
ask_rank(x);
}
}
else if(opt==4)
{
if(tot==0)
{
printf("0\n");
}
else
{
ask_sum(root,x);
}
}
else if(opt==5)
{
if(tot==0)
{
printf("0\n");
}
else
{
ask_front(x);
}
}
else if(opt==6)
{
if(tot==0)
{
printf("0\n");
}
else
{
ask_back(x);
}
}
}
return 0;
}
BZOJ3224普通平衡树——非旋转treap的更多相关文章
- BZOJ3223文艺平衡树——非旋转treap
此为平衡树系列第二道:文艺平衡树您需要写一种数据结构,来维护一个有序数列,其中需要提供以下操作: 翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 ...
- 4923: [Lydsy1706月赛]K小值查询 平衡树 非旋转Treap
国际惯例的题面:这种维护排序序列,严格大于的进行操作的题都很套路......我们按照[0,k],(k,2k],(2k,inf)分类讨论一下就好.显然第一个区间的不会变化,第二个区间的会被平移进第一个区 ...
- 【bzoj3224】Tyvj 1728 普通平衡树 01Trie姿势+平衡树的四种姿势 :splay,旋转Treap,非旋转Treap,替罪羊树
直接上代码 正所谓 人傻自带大常数 平衡树的几种姿势: AVL Red&Black_Tree 码量爆炸,不常用:SBT 出于各种原因,不常用. 常用: Treap 旋转 基于旋转操作和随机数 ...
- 平衡树及笛卡尔树讲解(旋转treap,非旋转treap,splay,替罪羊树及可持久化)
在刷了许多道平衡树的题之后,对平衡树有了较为深入的理解,在这里和大家分享一下,希望对大家学习平衡树能有帮助. 平衡树有好多种,比如treap,splay,红黑树,STL中的set.在这里只介绍几种常用 ...
- BZOJ3729Gty的游戏——阶梯博弈+巴什博弈+非旋转treap(平衡树动态维护dfs序)
题目描述 某一天gty在与他的妹子玩游戏.妹子提出一个游戏,给定一棵有根树,每个节点有一些石子,每次可以将不多于L的石子移动到父节点,询问将某个节点的子树中的石子移动到这个节点先手是否有必胜策略.gt ...
- [bzoj3196][Tyvj1730]二逼平衡树_树套树_位置线段树套非旋转Treap/树状数组套主席树/权值线段树套位置线段树
二逼平衡树 bzoj-3196 Tyvj-1730 题目大意:请写出一个维护序列的数据结构支持:查询给定权值排名:查询区间k小值:单点修改:查询区间内定值前驱:查询区间内定值后继. 注释:$1\le ...
- 关于非旋转treap的学习
非旋转treap的操作基于split和merge操作,其余操作和普通平衡树一样,复杂度保证方式与旋转treap差不多,都是基于一个随机的参数,这样构出的树树高为\(logn\) split 作用:将原 ...
- [NOIP]2017列队——旋转treap/非旋转treap
Sylvia 是一个热爱学习的女孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia所在的方阵中有n × m名学生,方阵的行数为 n,列数为m. 为了便 ...
- 旋转/非旋转treap的简单操作
treap(树堆) 是在二叉搜索树的基础上,通过维护随机附加域,使其满足堆性质,从而使树相对平衡的二叉树: 为什么可以这样呢? 因为在维护堆的时候可以同时保证搜索树的性质: (比如当一棵树的一个域满足 ...
随机推荐
- A2D JS框架 - AOP封装
AOP在js中的实现,先看看用法吧: var A2D = $.noConflict();//不要误会,此乃我自己写的A2D框架,非jQuery function fn1(name, age) { co ...
- 反射那点基础-Method
目录 1 获取 Method 1.1 方法 1.2 实例 2 Method 的方法 2.1 Java 方法基础知识 2.2 修饰符相关方法 2.2.1 获取修饰符 2.2.2 判断是否为 defaul ...
- LeetCode 657. Robot Return to Origin
There is a robot starting at position (0, 0), the origin, on a 2D plane. Given a sequence of its mov ...
- 《React Native 精解与实战》书籍连载「React 与 React Native 简介」
此文是我的出版书籍<React Native 精解与实战>连载分享,此书由机械工业出版社出版,书中详解了 React Native 框架底层原理.React Native 组件布局.组件与 ...
- Golang-教程
http://www.runoob.com/go/go-environment.html https://www.pythonav.cn/
- MySQL数据类型--日期和时间类型
MySQL中的多种时间和格式数据类型 日期和时间类型是为了方便在数据库中存储日期和时间而设计的.MySQL中有多种表示日期和时间的数据类型. 其中,year类型表示时间,date类型表示日期,time ...
- 每周分享之JS数组的使用
数组,一堆数字归为一组,就是一个数组,一堆对象放在一个组里,也是一个数组,概念很容易懂,说白了就是一个有限集合. JS数组的语法无法两种,插入和移除(语法自行科普).用处挺常见的,既然数组是一个集合, ...
- python文件、文件夹的移动、复制、删除、重命名
import os.path ,shutil shutil.copytree("G://qqfile","G://new_qqfile")# 第一个是原来的文件 ...
- openstack-KVM管理工具
一. virsh 通过libvirt API管理Hpervisor.node.domain,实现多数功能调用. 即统一管理多台计算机上的域. 1.管理其他服务器(node) (1)修改配置文件:vim ...
- [2017BUAA软工助教]第0次作业小结
BUAA软工第0次作业小结 零.题目 作业链接: This is a hyperlink 一.评分规则 本次作业满分10分: 按时提交有分 一周内补交得0分 超过一周不交或抄袭倒扣全部分数 评分规则如 ...