还有人把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的更多相关文章

  1. 模板—数据结构—LCT

    模板—数据结构—LCT Code: #include <cstdio> #include <algorithm> using namespace std; #define N ...

  2. 模板 - 数据结构 - 可持久化无旋Treap/PersistentFHQTreap

    有可能当树中有键值相同的节点时,貌似是要对Split和Merge均进行复制的,本人实测:只在Split的时候复制得到了一个WA,但只在Merge的时候复制还是AC,可能是恰好又躲过去了.有人说假如确保 ...

  3. [数据结构]Treap简介

    [写在前面的话] 如果想学Treap,请先了解BST和BST的旋转 二叉搜索树(BST)(百度百科):[here] 英文好的读者可以戳这里(维基百科) 自己的博客:关于旋转(很水,顶多就算是了解怎么旋 ...

  4. 算法模板——平衡树Treap 2

    实现功能:同平衡树Treap 1(BZOJ3224 / tyvj1728) 这次的模板有了不少的改进,显然更加美观了,几乎每个部分都有了不少简化,尤其是删除部分,这个参照了hzwer神犇的写法,在此鸣 ...

  5. 【模板】Treap

    Treap,又称树堆,是一种通过堆性质来维持BST平衡的数据结构.具体体现在对于树上每一个点来说,既有BST维护的值,又有一个堆维护的随机生成的值.维护平衡性的办法是根据堆维护的值的相对大小关系进行左 ...

  6. 算法模板——平衡树Treap

    实现功能如下——1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数,因输出最小的排名)4. 查询排名为x的数5. 求x的前驱(前驱定义为小于x,且最大 ...

  7. [SinGuLaRiTy] 复习模板-数据结构

    [SinGuLaRiTy-1040] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. 二维线段树 2D_Segment_Tree //示例:单 ...

  8. 模板汇总——treap

    1. 旋转treap. 思想:一颗权值BST + 一颗 随机数 最小堆. BZOJ - 3224 代码: #include<bits/stdc++.h> using namespace s ...

  9. 模板 - 数据结构 - 栈/Stack

    普通的栈大家都会写,STL的栈据说默认实现方式是deque,没关系反正deque跑得飞快. 这里收录的是一些奇怪的栈,当然双栈实现的队列收录在队列里面. 对顶栈 众所周知,栈可以维护一系列前缀和,包括 ...

随机推荐

  1. C# mailKit 发邮件 简单代码

    public static async Task<bool> SendMailAsync22(string Name, string receive, string sender, str ...

  2. vue 百度云上传文件PostObject

    百度云上传文件 API(PostObject) PostObject接口  : 接口描述 此接口使用HTML表单上传文件到指定bucket,用于实现通过浏览器上传文件到bucket.在PutObjec ...

  3. Django Rest framework实现流程

    目录 一 什么是restful架构 二 Django REST framework简介 三 Django REST framework原理 四 Django REST framework源码流程 五 ...

  4. iOS开发-NSArray

    忙了一上午,解决了几个bug,现在终于抽出来一点时间喝点水休息下, 想着系列这么浩大的一个工程,才刚刚开始写,不能断了,就跟写小说一样,既然是系列,那么就需要不停更... 好吧. 简单的说说iOS开发 ...

  5. [转]大牛们是怎么阅读 Android 系统源码的

    转自:http://www.zhihu.com/question/19759722 由于工作需要大量修改framework代码, 在AOSP(Android Open Source Project)源 ...

  6. aspx反射调用方法

    string name = base.Request["action"]; ]); if (obj2 != null) { s = obj2.ToString(); } 传入方法名 ...

  7. 实现对MySQL数据库进行分库/分表备份(shell脚本)

    工作中,往往数据库备份是件非常重要的事情,毕竟数据就是金钱,就是生命!废话不多,下面介绍一下:如何实现对MySQL数据库进行分库备份(shell脚本) Mysq数据库dump备份/还原语法: mysq ...

  8. String.getBytes()方法中的中文编码问题

    得到一个操作系统默认的编码格式的字节数组.这表示在不同的操作系统下,返回的东西不一样! byte[] a= "中".getBytes() String.getBytes(Strin ...

  9. python字典添加元素和删除元素

    1. 添加字典元素 方法一:直接添加,给定键值对 #pycharm aa = {'人才':60,'英语':'english','adress':'here'} print(aa) # {'人才': 6 ...

  10. Kotlin编译器使用及反编译分析

    在上一次对Kotlin进行了一个入门的介绍,并用IntelliJ IDEA来编写了一个Kotlin的HelloWorld,记得我们在最初学习J2SE的时候在编译运行都是通过javac.java命令来进 ...