BST-Treap名次树数组&指针实现板子 Ver1.0
这里只有板子没有原理QWQ
可实现
1.插入 x 数
2.删除 x 数(若有多个相同的数,只删除一个)
3.查询 x 数的排名(排名定义为比当前数小的数的个数 +1)
4.查询排名为 x 的数
5.求 x 的前驱(前驱定义为小于 x,且最大的数)
6.求 x 的后继(后继定义为大于 x,且最小的数)
原题 https://www.luogu.com.cn/problem/P3369
目前看来,指针板子相对数组板子相对好写,虽然时间稍快,但是空间稍劣,而且所有指针都要初始化为null,不初始化为null无法insert进去。
数组板子 374ms 2.78MB
指针板子 315ms 2.82MB
数组板子 374ms 2.78MB
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
#define IL inline
typedef long long LL;
const int N = 1e5 + 3;
struct Node {
int ch[2],v,sz,r,cnt;
IL bool operator < (const Node& rhs) const { return r < rhs.r;}
IL int cmp(int x) const {
if(x == v) return -1;
return x > v;
}
};
struct Treap {
int sz,root,ans;
Node tr[N];
IL void init() {tr[0].ch[0]=tr[0].ch[1]=tr[0].sz=tr[0].cnt=tr[0].r=0; root = 0;}
IL void upd(int o) { tr[o].sz=tr[tr[o].ch[0]].sz+tr[tr[o].ch[1]].sz+tr[o].cnt;}
IL void rotate(int &o,int d) {
int k = tr[o].ch[d^1]; tr[o].ch[d^1]=tr[k].ch[d]; tr[k].ch[d] = o;
upd(o); upd(k); o = k;
}
void insert(int &o,int x) {
if(o == 0) {
o=++sz;
tr[o].ch[0] = tr[o].ch[1] = 0;
tr[o].sz = tr[o].cnt=1;
tr[o].v = x; tr[o].r = rand();
return;
}
tr[o].sz++;
int d = tr[o].cmp(x);
if(d == -1) { tr[o].cnt++; return;}
insert(tr[o].ch[d],x);
if(tr[tr[o].ch[d]].r > tr[o].r) rotate(o,d^1);
upd(o);
}
void erase(int &o,int x) {
if(o == 0) return;
int d = tr[o].cmp(x);
if(d == -1) {
if(tr[o].cnt > 1) { tr[o].cnt--; tr[o].sz--; return;}
if(tr[o].ch[0]*tr[o].ch[1]==0) { o = tr[o].ch[0] + tr[o].ch[1];}
else {
int d2 = tr[tr[o].ch[0]].r > tr[tr[o].ch[1]].r;
rotate(o,d2); erase(tr[o].ch[d2],x);
}
}
else erase(tr[o].ch[d],x);
upd(o);
}
int query_rank(int o,int x) { //查询x的排名
if(o == 0) return 1;
if(tr[o].v==x) return tr[tr[o].ch[0]].sz+1;
else if(x > tr[o].v)
return tr[tr[o].ch[0]].sz+tr[o].cnt+query_rank(tr[o].ch[1],x);
else return query_rank(tr[o].ch[0],x);
}
int query_kth(int o,int x) { //查询排名为x的数
if(o == 0) return 0;
if(x <= tr[tr[o].ch[0]].sz) return query_kth(tr[o].ch[0],x);
else if(x>tr[tr[o].ch[0]].sz+tr[o].cnt)
return query_kth(tr[o].ch[1],x-tr[tr[o].ch[0]].sz-tr[o].cnt);
else return tr[o].v;
}
void query_pre(int o,int x) { // 查询x的前驱
if(o == 0) return;
if(tr[o].v < x) {
ans = o; query_pre(tr[o].ch[1],x);
}
else query_pre(tr[o].ch[0],x);
}
void query_sub(int o,int x) { // 查询x的后继
if(o == 0) return;
if(tr[o].v > x) {
ans = o; query_sub(tr[o].ch[0],x);
}
else query_sub(tr[o].ch[1],x);
}
IL void ins(int x) {insert(root,x); return;}
IL void del(int x) {erase(root,x); return;}
IL int rank(int x) {return query_rank(root,x);} //return rank of x
IL int kth(int x) {return query_kth(root,x);} // return the number,which rank=x.
IL int pre(int x) {ans=0; query_pre(root,x); return ans;}
IL int sub(int x) {ans=0; query_sub(root,x); return ans;}
};
Treap tr;
int main() {
int n; scanf("%d",&n);
int op,x;
tr.init();
for(int i=0;i<n;i++) {
scanf("%d%d",&op,&x);
switch(op) {
case 1: tr.ins(x); break;
case 2: tr.del(x); break;
case 3: printf("%d\n",tr.rank(x)); break;
case 4: printf("%d\n",tr.kth(x)); break;
case 5: printf("%d\n",tr.tr[tr.pre(x)].v); break;
case 6: printf("%d\n",tr.tr[tr.sub(x)].v); break;
}
}
}
指针板子 315ms 2.82MB
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
#define IL inline
typedef long long LL;
const int N = 1e5 + 3;
struct Node *null;
struct Node {
Node *ch[2];
int v,sz,r,cnt;
IL Node() {}
IL Node(int v):v(v) {ch[0]=ch[1]=null; r=rand(); sz=cnt=1;}
IL bool operator < (const Node& rhs) const { return r < rhs.r;}
IL int cmp(int x) const {
if(x == v) return -1;
return v < x;
}
IL void upd() { sz = ch[0] -> sz + ch[1] -> sz + cnt;}
};
IL void initnull() {null = new Node(); null->v=null->sz=null->r=null->cnt=0;}
IL void rotate(Node* &o,int d) {
Node *k = o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d] = o;
o->upd(); k->upd(); o = k;
}
void insert(Node* &o,int x) {
if(o == null) {o = new Node(x); return;}
o->sz++;
int d = o->cmp(x);
if(d == -1) {o->cnt++; return;}
insert(o->ch[d],x);
if(o->r < o->ch[d]->r) rotate(o,d^1);
o -> upd();
}
void erase(Node* &o,int x) {
if(o == null) return;
int d = o->cmp(x);
if(d == -1) {
Node* u = o;
if(o->cnt > 1) {o->cnt--; o->sz--; return;}
if(o->ch[0] != null && o->ch[1] != null) {
int d2 = o->ch[0]->r > o->ch[1]->r;
rotate(o,d2); erase(o->ch[d2],x);
}
else {
if(o->ch[0] == null) o = o->ch[1]; else o = o->ch[0];
delete u;
}
}
else erase(o->ch[d],x);
if(o != null) o->upd();
}
int query_rank(Node *o, int x) {
if(o == null) return 1;
if(o->v == x) return o->ch[0]->sz + 1;
else if(o->v < x) return o->ch[0]->sz + o->cnt + query_rank(o->ch[1],x);
else return query_rank(o->ch[0],x);
}
int query_kth(Node* o, int k) {
if(o == null) return 0;
if(k <= o->ch[0]->sz) return query_kth(o->ch[0],k);
else if(k > o->ch[0]->sz + o->cnt)
return query_kth(o->ch[1],k - o->ch[0]->sz - o->cnt);
return o->v;
}
Node *ans,*root;
void query_pre(Node* o,int x) {
if(o == null) return;
if(o->v < x) { ans = o; query_pre(o->ch[1],x);}
else query_pre(o->ch[0],x);
}
void query_sub(Node* o,int x) {
if(o == null) return;
if(x < o->v) { ans = o; query_sub(o->ch[0],x);}
else query_sub(o->ch[1],x);
}
IL void ins(int x) {insert(root,x);}
IL void del(int x) {erase(root,x);}
IL int rank(int x) {return query_rank(root,x);}
IL int kth(int x) {return query_kth(root,x);}
IL int pre(int x) {ans=null;query_pre(root,x);return ans->v;}
IL int sub(int x) {ans=null;query_sub(root,x);return ans->v;}
IL void init() { initnull(); ans = root = null;}
int main() {
int n; scanf("%d",&n);
int op,x;
init();
for(int i=0;i<n;i++) {
scanf("%d%d",&op,&x);
switch(op) {
case 1: ins(x); break;
case 2: del(x); break;
case 3: printf("%d\n",rank(x)); break;
case 4: printf("%d\n",kth(x)); break;
case 5: printf("%d\n",pre(x)); break;
case 6: printf("%d\n",sub(x)); break;
}
}
return 0;
}
BST-Treap名次树数组&指针实现板子 Ver1.0的更多相关文章
- 「模板」「讲解」Treap名次树
Treap实现名次树 前言 学平衡树的过程可以说是相当艰难.浏览Blog的过程中看到大量指针版平衡树,不擅长指针操作的我已经接近崩溃.于是,我想着一定要写一篇非指针实现的Treap的Blog. 具体如 ...
- UVa 1479 (Treap 名次树) Graph and Queries
这题写起来真累.. 名次树就是多了一个附加信息记录以该节点为根的树的总结点的个数,由于BST的性质再根据这个附加信息,我们可以很容易找到这棵树中第k大的值是多少. 所以在这道题中用一棵名次树来维护一个 ...
- LA 5031 Graph and Queries —— Treap名次树
离线做法,逆序执行操作,那么原本的删除边的操作变为加入边的操作,用名次树维护每一个连通分量的名次,加边操作即是连通分量合并操作,每次将结点数小的子树向结点数大的子树合并,那么单次合并复杂度O(n1lo ...
- POJ-1442 Black Box,treap名次树!
Black Box 唉,一天几乎就只做了这道题,成就感颇低啊! 题意:有一系列插入查找操作,插入每次 ...
- C语言提高 (4) 第四天 数组与数组作为参数时的数组指针
1昨日回顾 const int 和 int const是一样的 const char *p;值不变 char * const p; 指针不能变 编译器对参数的退化: 第三种模型: 三级指针 三级指针局 ...
- Treap 实现名次树
在主流STL版本中,set,map,都是BST实现的,具体来说是一种称为红黑树的动态平衡BST: 但是在竞赛中并不常用,因为红黑树过于复杂,他的插入 5 种,删除 6 中,代码量极大(如果你要改板子的 ...
- Treap和名次树
Treap名字的来源:Tree+Heap,正如名字一样,就是一颗简单的BST,一坨堆的合体.BST的不平衡的根本原因在于基于左<=根<=右的模式吃单调序列时候会无脑成长链,而Treap则添 ...
- uvalive 5031 Graph and Queries 名次树+Treap
题意:给你个点m条边的无向图,每个节点都有一个整数权值.你的任务是执行一系列操作.操作分为3种... 思路:本题一点要逆向来做,正向每次如果删边,复杂度太高.逆向到一定顺序的时候添加一条边更容易.详见 ...
- 模板——Treap实现名次树
Treap 是一种通过赋予结点随机权值的一种满足堆性质的二叉搜索树,它很好的解决了二叉搜索树顺序插入组成链式的局限性. 名次树是指在treap的每个结点中添加附加域size,表示以它为根的子树的总结点 ...
- hdu4585 Treap与名次树/STL map(C/C++)
hdu4585 题目地址:https://acm.dingbacode.com/showproblem.php?pid=4585 Shaolin Time Limit: 3000/1000 MS (J ...
随机推荐
- 浅析mvvm模式和mvc模式的区别和联系
三层架构与MVC模式 三层架构 三层架构是一种以实现"高内聚,底耦合"为目标,的代码架构方法,它将整个业务分为,表示层,业务层,数据访问层(Dao层). MVC模式 MVC模式是一 ...
- 使用open webui+ollama部署本地大模型
使用open webui+ollama部署本地大模型 上次使用了angthingllm + ollama部署了本地大模型,详情见:https://www.cnblogs.com/jokingremar ...
- VGA色块显示#VGA显示数字
VGA驱动色块显示 了解了VGA的显示原理和ADV7123控制后,再去实现色块显示就容易了. 像素坐标 跟显示色条不同,要在屏幕上不同的地方显示色块,需要用像素坐标来定位色块.其实,就是分别用行扫描的 ...
- B/S 结构系统的 缓存机制(Cookie) 以及基于 cookie 机制实现 oa 十天免登录的功能
B/S 结构系统的 缓存机制(Cookie) 以及基于 cookie 机制实现 oa 十天免登录的功能 @ 目录 B/S 结构系统的 缓存机制(Cookie) 以及基于 cookie 机制实现 oa ...
- pde复习笔记 第一章 波动方程 第三节 分离变量法
教材 谷超豪<数学物理方程>第四版,虽然我们老师用的第三版,但是除了页码对不上,习题多了一点,也似乎没有多少区别. 打算开个新栏专门总结一下pde的各种计算问题,在图书馆算的手麻了,但是习 ...
- VMware最小化安装Centos7.6-无桌面
目录 安装包工具 新建虚拟机 安装 centos 7.6 系统 终端登陆系统 设置ip地址 关闭防火墙 关闭 SELINUX SELINUX=enforcing 硬盘挂载 桥接上网方式 安装包工具 V ...
- vue子组件给父组件传值
子组件: <template> <div class="app"> <input @click="sendMsg" type=&q ...
- Linux下vim的常用命令总结
vim按d表示剪切 按dd剪切一行 vim命令:命令模式 /关键字 n继续向下查找 vim的多行注释: 1.按ctrl + v进入 visual block模式 2.按上下选中要注释的行 3.按大写字 ...
- 常回家看看之off_by_one
off_by_one这个漏洞比较特殊,它不像上一期的堆溢出,可以溢出很多字节,它只能溢出一个字节,在栈里面也可以通过这个漏洞修改返回地址什么的,在堆里面我们主要利用它来修改堆块的大小,形成fake_c ...
- Vue cli之创建组件
一般在开发中,我们会人为把组件分2个目录存放,一个代表的页面组件,另一个代表页面一部分的子组件. src/ |- views/ |- Home.vue |- components/ |- App.vu ...