模板 - 数据结构 - 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跑得飞快. 这里收录的是一些奇怪的栈,当然双栈实现的队列收录在队列里面. 对顶栈 众所周知,栈可以维护一系列前缀和,包括 ...
随机推荐
- Linux mount/unmount 挂载和卸载指令
对于Linux用户来讲,不论有几个分区,分别分给哪一个目录使用,它总归就是一个根目录.一个独立且唯一的文件结构 Linux中每个分区都是用来组成整个文件系统的一部分,她在用一种叫做“挂载”的处理方法, ...
- iview的table组件中加入超链接组件,可编辑组件,选择组件,日期组件
这篇文章主要介绍了iview的table组件中使用选择框,日期,可编辑表格,超链接等组件. 1.select选择组件 // tableColumn数组响应对象需要传入一个固定的option数组,如果该 ...
- 多个div并排不换行
1.所有div的父元素不换行 white-space: nowrap; 2.所有div设置为行内元素 display: inline-block; 基于java记账管理系统[尚学堂·百战程序员]
- How to : SAP PI Cache Refresh
Requirement : Identify various tools/resources available to perform SAP PI Cache refresh . Please no ...
- php中的特殊标签
参考:https://www.freebuf.com/column/212586.html 今天看到这篇文章讲到了ctf中的一些关于php标签的小姿势,我虽然不打ctf,但是平常做php的代码审计也经 ...
- SDL图解
1.什么是SDL 2.为什么要用SDL 3.SDL由哪几个阶段组成 用于规范公司web应用开发流程:安全需求分析.代码检查.安全测试... 4.微软的SDL实施流程
- js调用正则表达式
//验证是否为正整数 function isPositiveInteger(s) { var re = /^[0-9]+$/; return re.test(s); } if (exchangeCou ...
- c# List<Object>和List<实体>相互转化
开发的过程中总会遇到各种转化的问题,现在我做的开发接口中就遇到需要将List<Object> 中的Object又含有List<实体>归为一个list中,就是要list中没有Li ...
- CentOS7.X+LAMP+zabbix4.2环境下搭建Grafana6.1数据库可视化
1.GrafanaRPM包部署(yum install wget) wget https://dl.grafana.com/oss/release/grafana-6.1.4-1.x86_64.r ...
- [Python]pip install offline 如何离线pip安装包
痛点:目标机器无法连接公网,但是能使用rz.sz传输文件 思路:在能上网的机器是使用pip下载相关依赖包,然后传输至目标机器,进行安装 0. Install pip: http://pip-cn.re ...