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

普通平衡树

题目链接:luogu P3369

题目大意

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

思路

写 fhq Treap 之前突然发现自己剪贴板里面有个半年前写完的 Treap 没写题解,又发现没有一道 Treap 的题解,然后就过来补题解了。

有旋 Treap 其实旋转和 splay 差不多,但只是旋转的条件和 splay 不一样,splay 是看你询问的点,而 Treap 是直接用随机数给每个点一个优先级,然后维护一个以这个优先级为关键字的大根堆。

那其实就只有旋转和点的操作会不同,其它的操作和其他一般的平衡树都挺像的。

具体实现看代码吧。

代码

#include<cstdio> #include<cstdlib> #include<iostream> using namespace std; int n, root, op, x, tot, way, new_root; int key[100001], size[100001], sum[100001], son[100001][2], rd[100001]; void get_size(int x) { size[x] = size[son[x][0]] + size[son[x][1]] + sum[x]; return ; } void turn(int &root, int way) {//旋转 new_root = son[root][way ^ 1]; son[root][way ^ 1] = son[new_root][way]; son[new_root][way] = root; get_size(root); get_size(new_root); root = new_root; return ; } void push_num(int &root, int x) { if (!root) { root = ++tot; key[root] = x; size[root] = 1; sum[root] = 1; rd[root] = rand();//随机给一个用来比较的值 return ; } if (x == key[root]) { size[root]++; sum[root]++; return ; } way = x > key[root]; push_num(son[root][way], x); if (rd[root] < rd[son[root][way]])//如果不符合就要转 turn(root, way ^ 1); get_size(root); return ; } void delete_num(int &root, int x) {//转到最上面再删 if (!root) return ; if (key[root] != x) { way = x > key[root]; delete_num(son[root][way], x); get_size(root); return ; } if (!son[root][0] && !son[root][1]) { sum[root]--; size[root]--; if (sum[root] == 0) root = 0; get_size(root); return ; } if (son[root][0] && !son[root][1]) { turn(root, 1); delete_num(son[root][1], x); get_size(root); return ; } if (!son[root][0] && son[root][1]) { turn(root, 0); delete_num(son[root][0], x); get_size(root); return ; } if (son[root][0] && son[root][1]) { way = (rd[son[root][0]] < rd[son[root][1]]) ^ 1; turn(root, way); delete_num(son[root][way], x); get_size(root); return ; } return ; } int find_num(int root, int x) {//像普通平衡树的做法(后面都跟一般的平衡树差不多) if (!root) return 0; if (x == key[root]) return size[son[root][0]] + 1; if (x < key[root]) return find_num(son[root][0], x); if (x > key[root]) return size[son[root][0]] + sum[root] + find_num(son[root][1], x); } int find_key(int root, int x) { if (!root) return 0; if (x <= size[son[root][0]]) return find_key(son[root][0], x); if (x <= size[son[root][0]] + sum[root]) return key[root]; if (x > size[son[root][0]] + sum[root]) return find_key(son[root][1], x - size[son[root][0]] - sum[root]); } int pre(int root, int x) { if (!root) return -2147483647; if (x <= key[root]) return pre(son[root][0], x); if (x > key[root]) return max(pre(son[root][1], x), key[root]); } int suf(int root, int x) { if (!root) return 2147483647; if (x >= key[root]) return suf(son[root][1], x); if (x < key[root]) return min(suf(son[root][0], x), key[root]); } int main() { srand(114514); scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d %d", &op, &x); if (op == 1) { push_num(root, x); continue; } if (op == 2) { delete_num(root, x); continue; } if (op == 3) { printf("%d\n", find_num(root, x)); continue; } if (op == 4) { printf("%d\n", find_key(root, x)); continue; } if (op == 5) { printf("%d\n", pre(root, x)); continue; } if (op == 6) { printf("%d\n", suf(root, x)); continue; } } return 0; }

__EOF__

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