模板 - 数据结构 - 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跑得飞快. 这里收录的是一些奇怪的栈,当然双栈实现的队列收录在队列里面. 对顶栈 众所周知,栈可以维护一系列前缀和,包括 ...
随机推荐
- 解决SVN蓝色问号的问题
桌面或文件夹右键,选择TortoiseSVN->Settings打开设置对话框,选择Icon Overlays->Overlay Handlers->取消钩选Unversioned. ...
- Asp.netCore 是用的Socket 吗?
Asp.netCore 是用的Socket 的krestrel 用的是Socket! public static IWebHostBuilder CreateDefaultBuilder(string ...
- CTR预估-GBDT与LR实现
1.来源 本质上 GBDT+LR 是一种具有 stacking 思想的二分类器模型,所以可以用来解决二分类问题.这个方法出自于 Facebook 2014 年的论文 Practical Lessons ...
- VBA嵌套if语句
一个If或ElseIf语句可以嵌套在另一个If或ElseIf语句中.内部的If语句是根据最外层的If语句执行的.这使得VBScript能够轻松处理复杂的条件. 语法 以下是VBScript中嵌套的If ...
- 手写DAO框架(五)-DAO层实现
-------前篇:手写DAO框架(四)-SQL执行--------- 前言 通过上一篇,可以通过传入sql和对应的参数,可以执行sql并返回结果.但是对于一个DAO框架来说,要尽量的面向对象编程,也 ...
- pdm文件打开方式
转自:https://blog.csdn.net/qq_36855191/article/details/79299216 pdm打开网站:http://www.dmanywhere.cn/
- enumerateKeysAndObjectsUsingBlock 的用法
block是一个有序列的指令代码块,通常在代码中间花括号括起来的objective-c代码,但是它能被传递和被分配局部变量,然后作为一个参数来传递,基本上可以把花括号中间的代码保存到数据结构里.看起来 ...
- c# 子类的声明
- Mysql之数据库简介
一.什么是数据库? 据库即存放数据的仓库,只不过这个仓库是在计算机存储设备上,而且数据是按一定的格式存放的 过去人们将数据存放在文件柜里,现在数据量庞大,已经不再适用 数据库是长期存放在计算机内.有组 ...
- 剖析gcc -v输出
分析gcc -v的详细信息的意义 首先我们需要清楚一点,我们并不能完全弄清楚gcc -v的所有信息,因为毕竟我们并不是GCC编译器集合的实现者,对于这些信息,他们才是最清楚的.由于我们不能将所有的信息 ...