普通平衡树
题目大意
平衡树模板题,要求维护一些操作。 插入一个数,删除一个数,查询一个数的排名,查询排名一直的数,找前驱后继。
思路
这次我们用 fhq Treap(无旋 Treap)来做。
无旋 Treap 就是搞把树分裂与合并来实现对堆和二叉排序树的维护。
然后这里讲一下一些操作的实现。
插入输出很好想,两种排名也好搞。
而找前驱可以先按这个数割树,这个数放在右边,然后左边的树一直往右走。
而找后继可以先按这个数 +1 个数,使得这个数放在左边的最右边,然后右边的树一直往左走。
具体实现可以看看代码。
代码
#include<queue>
#include<cstdio>
#include<cstdlib>
using namespace std;
int ls[100001], rs[100001], val[100001], yj[100001], sz[100001], sum[100001];
int n, op, x, tot, root;
int make_new(int num) {
int now = ++tot;
sz[now] = 1;
ls[now] = rs[now] = 0;
val[now] = num;
yj[now] = rand();
return now;
}
void up(int now) {
sz[now] = sz[ls[now]] + sz[rs[now]] + 1;
}
pair <int, int> split_rnk(int now, int rnk) {
if (!now) return make_pair(0, 0);
if (!rnk) return make_pair(0, now);
pair <int, int> re;
if (sz[ls[now]] >= rnk) {
re = split_rnk(ls[now], rnk);
ls[now] = re.second;
up(now);
re.second = now;
}
else {
re = split_rnk(rs[now], rnk - sz[ls[now]] - 1);
rs[now] = re.first;
up(now);
re.first = now;
}
return re;
}
pair <int, int> split_val(int now, int num) {
if (!now) return make_pair(0, 0);
pair <int, int> re;
if (num <= val[now]) {
re = split_val(ls[now], num);
ls[now] = re.second;
up(now);
re.second = now;
}
else {
re = split_val(rs[now], num);
rs[now] = re.first;
up(now);
re.first = now;
}
return re;
}
int merge(int x, int y) {
if (!x) return y;
if (!y) return x;
if (yj[x] < yj[y]) {
rs[x] = merge(rs[x], y);
up(x);
return x;
}
else {
ls[y] = merge(x, ls[y]);
up(y);
return y;
}
}
void insert(int x) {
int now = make_new(x);
pair <int, int> y = split_val(root, x);
root = merge(merge(y.first, now), y.second);
}
void delete_(int now) {
pair <int, int> x = split_val(root, now);
pair <int, int> y = split_rnk(x.second, 1);
root = merge(x.first, y.second);
}
int ask_rnk(int now) {
pair <int, int> x = split_val(root, now);
int re = sz[x.first] + 1;
root = merge(x.first, x.second);
return re;
}
int ask_val(int now) {
pair <int, int> x = split_rnk(root, now - 1);
pair <int, int> y = split_rnk(x.second, 1);
int re = val[y.first];
root = merge(x.first, merge(y.first, y.second));
return re;
}
int get_pre(int now) {
pair <int, int> x = split_val(root, now);
int X = x.first, Y = 0;
while (X) {
Y = X;
X = rs[X];
}
root = merge(x.first, x.second);
return val[Y];
}
int get_nxt(int now) {
pair <int, int> x = split_val(root, now + 1);
int X = x.second, Y = 0;
while (X) {
Y = X;
X = ls[X];
}
root = merge(x.first, x.second);
return val[Y];
}
int main() {
srand(1919810);
scanf("%d", &n);
while (n--) {
scanf("%d %d", &op, &x);
if (op == 1) {
insert(x);
continue;
}
if (op == 2) {
delete_(x);
continue;
}
if (op == 3) {
printf("%d\n", ask_rnk(x));
continue;
}
if (op == 4) {
printf("%d\n", ask_val(x));
continue;
}
if (op == 5) {
printf("%d\n", get_pre(x));
continue;
}
if (op == 6) {
printf("%d\n", get_nxt(x));
continue;
}
}
return 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现