【luogu P3369】普通平衡树(fhq Treap 做法)

普通平衡树

题目链接:luogu P3369

题目大意

平衡树模板题,要求维护一些操作。 插入一个数,删除一个数,查询一个数的排名,查询排名一直的数,找前驱后继。

思路

这次我们用 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__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/luogu_P3369_fhqTreap.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(84)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示