题目链接:P3369 【模板】普通平衡树

题意

构造一种数据结构满足给出的 6 种操作。

思路

平衡树

平衡树的模板题。

先学习了一下 Treap。

Treap 在插入结点时给该结点随机生成一个额外的权值,然后用该权值维护一个大根堆,如果某个结点不满足大根堆的性质,就通过旋转与父节点交换。

对于删除某个结点,通过不断向下旋转直至变成叶子结点,然后直接删除即可。

模板来自《算法竞赛进阶指南》

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f; struct Treap {
int l, r;
int val, dat;
int cnt, size;
} a[maxn];
int tot, root;
int n; int new_node(int val) {
a[++tot].val = val;
a[tot].dat = rand();
a[tot].cnt = a[tot].size = 1;
return tot;
} void update(int p) {
a[p].size = a[a[p].l].size + a[a[p].r].size + a[p].cnt;
} void build() {
new_node(-inf), new_node(inf);
root = 1, a[1].r = 2;
update(root);
} int get_rank(int p, int val) {
if (p == 0) return 0;
if (val == a[p].val) return a[a[p].l].size + 1;
if (val < a[p].val) return get_rank(a[p].l, val);
return get_rank(a[p].r, val) + a[a[p].l].size + a[p].cnt;
} int get_val(int p, int rank) {
if (p == 0) return inf;
if (a[a[p].l].size >= rank) return get_val(a[p].l, rank);
if (a[a[p].l].size + a[p].cnt >= rank) return a[p].val;
return get_val(a[p].r, rank - a[a[p].l].size - a[p].cnt);
} // 右旋
void zig(int &p) {
int q = a[p].l;
a[p].l = a[q].r, a[q].r = p, p = q;
update(a[p].r), update(p);
} // 左旋
void zag(int &p) {
int q = a[p].r;
a[p].r = a[q].l, a[q].l = p, p = q;
update(a[p].l), update(p);
} void add(int &p, int val) {
if (p == 0) {
p = new_node(val);
return;
}
if (val == a[p].val) {
a[p].cnt++;
} else if (val < a[p].val) {
add(a[p].l, val);
if (a[p].dat < a[a[p].l].dat) zig(p);
} else {
add(a[p].r, val);
if (a[p].dat < a[a[p].r].dat) zag(p);
}
update(p);
} int get_pre(int val) {
int ans = 1; // a[1].val==-inf
int p = root;
while (p) {
if (val == a[p].val) {
if (a[p].l > 0) {
p = a[p].l;
while (a[p].r > 0) p = a[p].r;
ans = p;
}
break;
}
if (a[p].val < val && a[p].val > a[ans].val) ans = p;
p = val < a[p].val ? a[p].l : a[p].r;
}
return a[ans].val;
} int get_next(int val) {
int ans = 2; // a[2].val==inf
int p = root;
while (p) {
if (val == a[p].val) {
if (a[p].r > 0) {
p = a[p].r;
while (a[p].l > 0) p = a[p].l;
ans = p;
}
break;
}
if (a[p].val > val && a[p].val < a[ans].val) ans = p;
p = val < a[p].val ? a[p].l : a[p].r;
}
return a[ans].val;
} // 把非叶子结点旋转至叶子结点后直接删除
void remove(int &p, int val) {
if (p == 0) return;
if (val == a[p].val) {
if (a[p].cnt > 1) {
a[p].cnt--, update(p);
return;
}
if (a[p].l || a[p].r) { // 不是叶子节点,向下旋转
if (a[p].r == 0 || a[a[p].l].dat > a[a[p].r].dat)
zig(p), remove(a[p].r, val);
else
zag(p), remove(a[p].l, val);
update(p);
}
else p = 0; // 叶子节点,删除
return;
}
val < a[p].val ? remove(a[p].l, val) : remove(a[p].r, val);
update(p);
} int main() {
build();
cin >> n;
while (n--) {
int op, x;
cin >> op >> x; if(op == 1) {
add(root, x);
} else if(op == 2) {
remove(root, x);
} else if(op == 3) {
cout << get_rank(root, x) - 1 << endl;
} else if(op == 4) {
cout << get_val(root, x + 1) << endl;
} else if(op == 5) {
cout << get_pre(x) << endl;
} else {
cout << get_next(x) << endl;
}
}
return 0;
}

洛谷 P3369 【模板】普通平衡树 (Treap)的更多相关文章

  1. 洛谷.3369.[模板]普通平衡树(fhq Treap)

    题目链接 第一次(2017.12.24): #include<cstdio> #include<cctype> #include<algorithm> //#def ...

  2. 【洛谷P3369】普通平衡树——Splay学习笔记(一)

    二叉搜索树(二叉排序树) 概念:一棵树,若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值: 它的左.右子树也分别为二叉搜索树 ...

  3. 洛谷.3369.[模板]普通平衡树(Splay)

    题目链接 第一次写(2017.11.7): #include<cstdio> #include<cctype> using namespace std; const int N ...

  4. 洛谷.3391.[模板]文艺平衡树(Splay)

    题目链接 //注意建树 #include<cstdio> #include<algorithm> const int N=1e5+5; //using std::swap; i ...

  5. 洛谷P3369 【模板】普通平衡树(Treap/SBT)

    洛谷P3369 [模板]普通平衡树(Treap/SBT) 平衡树,一种其妙的数据结构 题目传送门 题目描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 插入x数 删除 ...

  6. 【洛谷P3369】【模板】普通平衡树题解

    [洛谷P3369][模板]普通平衡树题解 题目链接 题意: 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3 ...

  7. 洛谷P3369普通平衡树(Treap)

    题目传送门 转载自https://www.cnblogs.com/fengzhiyuan/articles/7994428.html,转载请注明出处 Treap 简介 Treap 是一种二叉查找树.它 ...

  8. 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)

    To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...

  9. luoguP3369[模板]普通平衡树(Treap/SBT) 题解

    链接一下题目:luoguP3369[模板]普通平衡树(Treap/SBT) 平衡树解析 #include<iostream> #include<cstdlib> #includ ...

  10. 绝对是全网最好的Splay 入门详解——洛谷P3369&BZOJ3224: Tyvj 1728 普通平衡树 包教包会

    平衡树是什么东西想必我就不用说太多了吧. 百度百科: 一个月之前的某天晚上,yuli巨佬为我们初步讲解了Splay,当时接触到了平衡树里的旋转等各种骚操作,感觉非常厉害.而第二天我调Splay的模板竟 ...

随机推荐

  1. 建站手册-浏览器信息:Netscape 浏览器

    ylbtech-建站手册-浏览器信息:Netscape 浏览器 1.返回顶部 1. http://www.w3school.com.cn/browsers/browsers_netscape.asp ...

  2. DCloud-Video:Html5 Video 实现方案

    ylbtech-DCloud-Video:Html5 Video 实现方案 1.返回顶部 1.1. http://ask.dcloud.net.cn/article/569 1.2. 一. Html5 ...

  3. django的model继承abstract,proxy,managed

    https://www.cnblogs.com/wangwei916797941/p/9525127.html?from=timeline

  4. docker-compose 搭建 Redis Sentinel 测试环境

    docker-compose 搭建 Redis Sentinel 测试环境 本文介绍如何使用 docker-compose 快速搭建一个 Redis Sentinel 测试环境.其中 Redis 集群 ...

  5. WebGPU学习(九):学习“fractalCube”示例

    大家好,本文学习Chrome->webgpu-samplers->fractalCube示例. 上一篇博文: WebGPU学习(八):学习"texturedCube"示 ...

  6. 阻抗匹配 及 SI9000 使用

    1. 阻抗匹配 1. 波长 * 频率 = 光速(3*10^8) 2. PCB走线什么时候需要做阻抗匹配? 不主要看频率,而关键是看信号的边沿陡峭程度,即信号的上升/下降时间,一般认为如果信号的上升/下 ...

  7. ztree 数组和树结构互转算法

    //树转化为数组transformToArrayFormat: function (setting, nodes) { if (!nodes) return []; var childKey = se ...

  8. 使用 C++ 编写的基础 Windows 服务 (CppWindowsService)

    最近项目中涉及到使用C++写一个后台服务程序,找了很多资料,还是使用Google搜索找到了比较详细点的资料,就是从微软官方MSDN的例子,如下: 使用 C++ 编写的基础 Windows 服务 (Cp ...

  9. scp指定端口 从远程机器复制目录到本机器目录

    scp -P 22622 -r root@192.168.70.63:/root/iNmon ./ -P port  注意是大写的P, port是指定数据传输用到的端口 root@192.168.70 ...

  10. Queue与Deque的区别

    前言 ​ 在研究java集合源码的时候,发现了一个很少用但是很有趣的点:Queue以及Deque,平常在写leetcode经常用LinkedList向上转型Deque作为栈或者队列使用,但是一直都不知 ...