模板 - 数据结构 - Treap
还有人把Treap叫做树堆的,但是常用名还是叫做Treap的比较多。
不进行任何封装的,带求和操作的,一个节点存放多个元素的最普通的Treap。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls ch[id][0]
#define rs ch[id][1]
const int INF = 1e9;
const int MAXN = 1000000 + 5;
int ch[MAXN][2], dat[MAXN];
int val[MAXN];
int cnt[MAXN];
int siz[MAXN];
ll sum[MAXN];
int tot, root;
inline void Init() {
tot = 0;
root = 0;
}
inline int NewNode(int v, int num) {
int id = ++tot;
ls = rs = 0;
dat[id] = rand();
val[id] = v;
cnt[id] = num;
siz[id] = num;
sum[id] = 1ll * num * v;
return id;
}
inline void PushUp(int id) {
siz[id] = siz[ls] + siz[rs] + cnt[id];
sum[id] = sum[ls] + sum[rs] + 1ll * cnt[id] * val[id];
}
inline void Rotate(int &id, int d) {
int temp = ch[id][d ^ 1];
ch[id][d ^ 1] = ch[temp][d];
ch[temp][d] = id;
id = temp;
PushUp(ch[id][d]);
PushUp(id);
}
//插入num个v
inline void Insert(int &id, int v, int num) {
if(!id)
id = NewNode(v, num);
else {
if(v == val[id])
cnt[id] += num;
else {
int d = val[id] > v ? 0 : 1;
Insert(ch[id][d], v, num);
if(dat[id] < dat[ch[id][d]])
Rotate(id, d ^ 1);
}
PushUp(id);
}
}
//删除至多num个v
void Remove(int &id, int v, int num) {
if(!id)
return;
else {
if(v == val[id]) {
if(cnt[id] > num) {
cnt[id] -= num;
PushUp(id);
} else if(ls || rs) {
if(!rs || dat[ls] > dat[rs])
Rotate(id, 1), Remove(rs, v, num);
else
Rotate(id, 0), Remove(ls, v, num);
PushUp(id);
} else
id = 0;
} else {
val[id] > v ? Remove(ls, v, num) : Remove(rs, v, num);
PushUp(id);
}
}
}
//查询v的排名,排名定义为<v的数的个数+1。
int GetRank(int id, int v) {
int res = 1;
while(id) {
if(val[id] > v)
id = ls;
else if(val[id] == v) {
res += siz[ls];
break;
} else {
res += siz[ls] + cnt[id];
id = rs;
}
}
return res;
}
//查询排名为rk的数,rk必须是正整数,rk过大返回无穷
int GetValue(int id, int rk) {
int res = INF;
while(id) {
if(siz[ls] >= rk)
id = ls;
else if(siz[ls] + cnt[id] >= rk) {
res = val[id];
break;
} else {
rk -= siz[ls] + cnt[id];
id = rs;
}
}
return res;
}
//查询v的前驱的值(<v的第一个节点的值),不存在前驱返回负无穷
int GetPrev(int id, int v) {
int res = -INF;
while(id) {
if(val[id] < v)
res = val[id], id = rs;
else
id = ls;
}
return res;
}
//查询v的后继的值(>v的第一个节点的值),不存在后继返回无穷
int GetNext(int id, int v) {
int res = INF;
while(id) {
if(val[id] > v)
res = val[id], id = ls;
else
id = rs;
}
return res;
}
//查询小于等于v的数的和
ll GetSumValue(int id, int v) {
ll res = 0;
while(id) {
if(val[id] > v)
id = ls;
else if(val[id] == v) {
res += sum[ls] + 1ll * cnt[id] * val[id];
break;
} else {
res += sum[ls] + 1ll * cnt[id] * val[id];
id = rs;
}
}
return res;
}
//查询前rk个数的和,rk必须是正整数
ll GetSumRank(int id, int rk) {
ll res = 0;
while(id) {
if(siz[ls] >= rk)
id = ls;
else if(siz[ls] + cnt[id] >= rk) {
res += sum[ls] + 1ll * (rk - siz[ls]) * val[id];
break;
} else {
res += sum[ls] + 1ll * cnt[id] * val[id];
rk -= siz[ls] + cnt[id];
id = rs;
}
}
return res;
}
封装了val的,速度略微下降,因为是键值对所以求和类的函数变得没什么意义。
struct TreapNode {
int val1, val2;
TreapNode() {}
TreapNode(int val1, int val2): val1(val1), val2(val2) {}
bool operator<(const TreapNode& tn)const {
return val1 < tn.val1;
}
bool operator<=(const TreapNode& tn)const {
return val1 <= tn.val1;
}
bool operator==(const TreapNode& tn)const {
return val1 == tn.val1;
}
bool operator>=(const TreapNode& tn)const {
return val1 >= tn.val1;
}
bool operator>(const TreapNode& tn)const {
return val1 > tn.val1;
}
} TNINF(INF, INF);
/*#define TreapNode pii
TreapNode TNINF(INF, INF);*/
struct Treap {
#define ls ch[id][0]
#define rs ch[id][1]
static const int MAXN = 200000;
int ch[MAXN + 5][2], dat[MAXN + 5];
TreapNode val[MAXN + 5];
int cnt[MAXN + 5];
int siz[MAXN + 5];
int tot, root;
void Init() {
tot = 0;
root = 0;
}
int NewNode(TreapNode v, int num) {
int id = ++tot;
ls = rs = 0;
dat[id] = rand();
val[id] = v;
cnt[id] = num;
siz[id] = num;
return id;
}
void PushUp(int id) {
siz[id] = siz[ls] + siz[rs] + cnt[id];
}
void Rotate(int &id, int d) {
int temp = ch[id][d ^ 1];
ch[id][d ^ 1] = ch[temp][d];
ch[temp][d] = id;
id = temp;
PushUp(ch[id][d]);
PushUp(id);
}
//插入num个v
void _Insert(int &id, TreapNode v, int num) {
if(!id)
id = NewNode(v, num);
else {
if(v == val[id])
cnt[id] += num;
else {
int d = val[id] > v ? 0 : 1;
_Insert(ch[id][d], v, num);
if(dat[id] < dat[ch[id][d]])
Rotate(id, d ^ 1);
}
PushUp(id);
}
}
//删除至多num个v
void _Remove(int &id, TreapNode v, int num) {
if(!id)
return;
else {
if(v == val[id]) {
if(cnt[id] > num) {
cnt[id] -= num;
PushUp(id);
} else if(ls || rs) {
if(!rs || dat[ls] > dat[rs])
Rotate(id, 1), _Remove(rs, v, num);
else
Rotate(id, 0), _Remove(ls, v, num);
PushUp(id);
} else
id = 0;
} else {
val[id] > v ? _Remove(ls, v, num) : _Remove(rs, v, num);
PushUp(id);
}
}
}
//查询v的排名,排名定义为<v的数的个数+1。
int _GetRank(int id, TreapNode v) {
int res = 1;
while(id) {
if(val[id] > v)
id = ls;
else if(val[id] == v) {
res += siz[ls];
break;
} else {
res += siz[ls] + cnt[id];
id = rs;
}
}
return res;
}
//查询排名为rk的数,rk必须是正整数,rk过大返回无穷
TreapNode _GetValue(int id, int rk) {
TreapNode res = TNINF;
while(id) {
if(siz[ls] >= rk)
id = ls;
else if(siz[ls] + cnt[id] >= rk) {
res = val[id];
break;
} else {
rk -= siz[ls] + cnt[id];
id = rs;
}
}
return res;
}
int Size() {
return siz[root];
}
void Insert(TreapNode v, int num = 1) {
_Insert(root, v, num);
}
void Remove(TreapNode v, int num = INF) {
_Remove(root, v, num);
}
int GetRank(TreapNode v) {
return _GetRank(root, v);
}
TreapNode GetValue(int rk) {
return _GetValue(root, rk);
}
#undef ls
#undef rs
}
模板 - 数据结构 - Treap的更多相关文章
- 模板—数据结构—LCT
模板—数据结构—LCT Code: #include <cstdio> #include <algorithm> using namespace std; #define N ...
- 模板 - 数据结构 - 可持久化无旋Treap/PersistentFHQTreap
有可能当树中有键值相同的节点时,貌似是要对Split和Merge均进行复制的,本人实测:只在Split的时候复制得到了一个WA,但只在Merge的时候复制还是AC,可能是恰好又躲过去了.有人说假如确保 ...
- [数据结构]Treap简介
[写在前面的话] 如果想学Treap,请先了解BST和BST的旋转 二叉搜索树(BST)(百度百科):[here] 英文好的读者可以戳这里(维基百科) 自己的博客:关于旋转(很水,顶多就算是了解怎么旋 ...
- 算法模板——平衡树Treap 2
实现功能:同平衡树Treap 1(BZOJ3224 / tyvj1728) 这次的模板有了不少的改进,显然更加美观了,几乎每个部分都有了不少简化,尤其是删除部分,这个参照了hzwer神犇的写法,在此鸣 ...
- 【模板】Treap
Treap,又称树堆,是一种通过堆性质来维持BST平衡的数据结构.具体体现在对于树上每一个点来说,既有BST维护的值,又有一个堆维护的随机生成的值.维护平衡性的办法是根据堆维护的值的相对大小关系进行左 ...
- 算法模板——平衡树Treap
实现功能如下——1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数,因输出最小的排名)4. 查询排名为x的数5. 求x的前驱(前驱定义为小于x,且最大 ...
- [SinGuLaRiTy] 复习模板-数据结构
[SinGuLaRiTy-1040] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. 二维线段树 2D_Segment_Tree //示例:单 ...
- 模板汇总——treap
1. 旋转treap. 思想:一颗权值BST + 一颗 随机数 最小堆. BZOJ - 3224 代码: #include<bits/stdc++.h> using namespace s ...
- 模板 - 数据结构 - 栈/Stack
普通的栈大家都会写,STL的栈据说默认实现方式是deque,没关系反正deque跑得飞快. 这里收录的是一些奇怪的栈,当然双栈实现的队列收录在队列里面. 对顶栈 众所周知,栈可以维护一系列前缀和,包括 ...
随机推荐
- C# mailKit 发邮件 简单代码
public static async Task<bool> SendMailAsync22(string Name, string receive, string sender, str ...
- vue 百度云上传文件PostObject
百度云上传文件 API(PostObject) PostObject接口 : 接口描述 此接口使用HTML表单上传文件到指定bucket,用于实现通过浏览器上传文件到bucket.在PutObjec ...
- Django Rest framework实现流程
目录 一 什么是restful架构 二 Django REST framework简介 三 Django REST framework原理 四 Django REST framework源码流程 五 ...
- iOS开发-NSArray
忙了一上午,解决了几个bug,现在终于抽出来一点时间喝点水休息下, 想着系列这么浩大的一个工程,才刚刚开始写,不能断了,就跟写小说一样,既然是系列,那么就需要不停更... 好吧. 简单的说说iOS开发 ...
- [转]大牛们是怎么阅读 Android 系统源码的
转自:http://www.zhihu.com/question/19759722 由于工作需要大量修改framework代码, 在AOSP(Android Open Source Project)源 ...
- aspx反射调用方法
string name = base.Request["action"]; ]); if (obj2 != null) { s = obj2.ToString(); } 传入方法名 ...
- 实现对MySQL数据库进行分库/分表备份(shell脚本)
工作中,往往数据库备份是件非常重要的事情,毕竟数据就是金钱,就是生命!废话不多,下面介绍一下:如何实现对MySQL数据库进行分库备份(shell脚本) Mysq数据库dump备份/还原语法: mysq ...
- String.getBytes()方法中的中文编码问题
得到一个操作系统默认的编码格式的字节数组.这表示在不同的操作系统下,返回的东西不一样! byte[] a= "中".getBytes() String.getBytes(Strin ...
- python字典添加元素和删除元素
1. 添加字典元素 方法一:直接添加,给定键值对 #pycharm aa = {'人才':60,'英语':'english','adress':'here'} print(aa) # {'人才': 6 ...
- Kotlin编译器使用及反编译分析
在上一次对Kotlin进行了一个入门的介绍,并用IntelliJ IDEA来编写了一个Kotlin的HelloWorld,记得我们在最初学习J2SE的时候在编译运行都是通过javac.java命令来进 ...