代码
/* Treap : 完整版 */
struct Treap {
private:
static const int TREAP_MAXN = 2e5 + 5;
static const ll LINF = 0x3f3f3f3f3f3f3f3fLL;
int root, top, del[TREAP_MAXN];
int ch[TREAP_MAXN][2], rnd[TREAP_MAXN];
public:
ll cnt[TREAP_MAXN], siz[TREAP_MAXN];
ll val[TREAP_MAXN], sum[TREAP_MAXN];
private:
#define ls ch[u][0]
#define rs ch[u][1]
int NewNode(ll v, ll c) {
int u = del[0] ? (del[del[0]--]) : ++top;
ls = rs = 0, rnd[u] = rand();
cnt[u] = siz[u] = c;
val[u] = v, sum[u] = c * v;
return u;
}
void PushUp(int u) {
siz[u] = siz[ls] + siz[rs] + cnt[u];
sum[u] = sum[ls] + sum[rs] + cnt[u] * val[u];
}
void Rotate(int &u, int d) {
int t = ch[u][d ^ 1];
ch[u][d ^ 1] = ch[t][d], ch[t][d] = u, u = t;
PushUp(ch[u][d]), PushUp(u);
}
void InsertHelp(int &u, ll v, ll c) {
if (!u) {
u = NewNode(v, c);
return;
} else if (v == val[u]) {
cnt[u] += c;
} else {
int d = val[u] < v;
InsertHelp(ch[u][d], v, c);
if (rnd[u] < rnd[ch[u][d]]) Rotate(u, d ^ 1);
}
PushUp(u);
}
void RemoveHelp(int &u, ll v, ll c) {
if (!u) {
return;
} else if (v == val[u]) {
if (cnt[u] > c) {
cnt[u] -= c;
} else if (ls || rs) {
int d = (!rs || rnd[ls] > rnd[rs]);
Rotate(u, d), RemoveHelp(ch[u][d], v, c);
} else {
del[++del[0]] = u, u = 0;
return;
}
} else {
RemoveHelp(ch[u][val[u] < v], v, c);
}
PushUp(u);
}
ll GetRankHelp(int u, ll v) {
if (!u) {
return 0;
} else if (val[u] == v) {
return siz[ls];
} else if (val[u] > v) {
return GetRankHelp(ls, v);
} else {
return siz[ls] + cnt[u] + GetRankHelp(rs, v);
}
}
ll GetValueHelp(int u, ll r) {
if (!u) {
return LINF;
} else if (siz[ls] < r && siz[u] - siz[rs] >= r) {
return val[u];
} else if (siz[ls] >= r) {
return GetValueHelp(ls, r);
} else {
return GetValueHelp(rs, r - siz[u] + siz[rs]);
}
}
ll GetPrevHelp(int u, ll v) {
if (!u) {
return -LINF;
} else if (val[u] < v) {
return max(val[u], GetPrevHelp(rs, v));
} else {
return GetPrevHelp(ls, v);
}
}
ll GetNextHelp(int u, ll v) {
if (!u) {
return LINF;
} else if (val[u] > v) {
return min(val[u], GetNextHelp(ls, v));
} else {
return GetNextHelp(rs, v);
}
}
ll GetSumValueHelp(int u, ll v) {
if (!u) {
return 0;
} else if (val[u] == v) {
return sum[u] - sum[rs];
} else if (val[u] > v) {
return GetSumValueHelp(ls, v);
} else {
return sum[u] - sum[rs] + GetSumValueHelp(rs, v);
}
}
ll GetSumRankHelp(int u, ll r) {
if (!u) {
return 0;
} else if (siz[ls] < r && siz[u] - siz[rs] >= r) {
return sum[ls] + (r - siz[ls]) * val[u];
} else if (siz[ls] >= r) {
return GetSumRankHelp(ls, r);
} else {
return sum[u] - sum[rs] + GetSumRankHelp(rs, r - siz[ls] + cnt[u]);
}
}
#undef ls
#undef rs
public:
void Init() { top = 0, root = 0; }
void Insert(ll v, ll c = 1) { InsertHelp(root, v, c); }
void Remove(ll v, ll c = 1) { RemoveHelp(root, v, c); }
ll GetRank(ll v) { return GetRankHelp(root, v) + 1; }
ll GetValue(ll r) { return GetValueHelp(root, r); }
ll GetPrev(ll v) { return GetPrevHelp(root, v); }
ll GetNext(ll v) { return GetNextHelp(root, v); }
ll GetSumValue(ll v) { return GetSumValueHelp(root, v); }
ll GetSumRank(ll r) { return GetSumRankHelp(root, r); }
} treap;
使用说明
节点:指Treap的节点,代码中用u表示
元素:指val中存储的值,代码中用v表示
注意区分节点和元素的区别。在这个实现中,节点和元素的权值是一一对应的,相同权值的元素会累计到同一个节点内。
以下字段可能涉及扩展性,可能需要修改:
TREAP_MAXN; // Treap能容纳的最大节点数
LINF; // 元素权值的正无穷大
cnt[u]; // 节点u表示的元素数量
siz[u]; // 节点u的子树的元素数量和
val[u]; // 节点u表示的元素权值
sum[u]; // 节点u的子树的元素权值和
// 以下“排名”定义为<v的元素数量+1,为正整数
int NewNode(ll v, ll c); // 新建一个节点,表示c个权值为v的元素
void PushUp(int u); // 重新计算节点u的信息
void InsertHelp(int &u, ll v, ll c); // 向节点u的子树插入c个权值为v的元素
void RemoveHelp(int &id, ll v, ll c); // 从节点u的子树删除至多c个权值为v的元素
ll GetRankHelp(int u, ll v); // 查询节点u的子树中权值为v的元素的排名-1
ll GetValueHelp(int u, ll r); // 查询节点u的子树中排名为r的元素的权值,若不存在返回LINF
ll GetPrevHelp(int u, ll v); // 查询节点u的子树中<v的元素的权值的最大值,若不存在返回-LINF
ll GetNextHelp(int u, ll v); // 查询节点u的子树中>v的元素的权值的最小值,若不存在返回LINF
ll GetSumValueHelp(int u, ll v); // 查询节点u的子树中权值<=v的元素的权值和
ll GetSumRankHelp(int u, ll r); // 查询节点u的子树中排名<=r的元素的权值和
void Init(); // 初始化Treap,清空所有节点和回收栈
void Insert(ll v, ll c); // 向Treap插入c个权值为v的元素
void Remove(ll v, ll c); // 从Treap删除至多c个权值为v的元素
ll GetRank(ll v); // 查询Treap中权值为v的元素的排名
ll GetValue(ll r); // 查询Treap中排名为r的元素的权值
ll GetPrev(ll v); // 查询Treap中权值为v的元素的前驱节点的元素的权值,若不存在返回-LINF
ll GetNext(ll v); // 查询Treap中权值为v的元素的后继节点的元素的权值,若不存在返回LINF
ll GetSumValue(ll v); // 查询Treap中权值<=v的元素的权值和
ll GetSumRank(ll r); // 查询Treap中排名<=r的元素的权值和
注意:这里为了方便,新建节点时使用了rand(),这会导致不同平台上运行结果很可能会有差异!
评价
性能特点:
- 在线算法
- 时间复杂度基于元素数量,且为期望复杂度
- 空间复杂度基于元素数量
- 运行的常数较小
- 使用懒标记维护较简洁
- 带旋转操作,不能可持久化
- 不像其他数据结构拥有无法取代的“特长”,不同场景下都可以被替代,甚至可以不学
与Splay对比:
Treap一般情况下常数较小,维护较简洁,时间复杂度为期望复杂度,但不能维护序列操作,也不支持LCT
与动态开点权值线段树和01Trie对比:
Treap的时间复杂度和空间复杂度都与值域无关,一般而言节省至少30%,但是不能维护异或操作,也不方便可持久化