非旋treap (fhq treap) 指针版
传送门
看了一圈,好像真的没什么用指针的呢。。
明明觉得指针很好看(什么??你说RE???听不见听不见)
其实我觉得用数组的话不RE直接WA调起来不是更困难嘛,毕竟通过gdb还可以知道哪里RE,WA就不知道咋回事了,是不是很有道理,虽然我还是调了几小时
我写的是fhq treap,核心是split和merge操作,思想高赞dalao都讲得很清楚,我语文弱渣就不班门弄斧了,主要是想提供一个指针版的参考吧QAQ
我真的是一整天都在搞分裂(split),有种要进入七月枪毙名单的赶脚,慌张.jpg
#include<bits/stdc++.h>
#define LL long long
#define fr(i,x,y) for(int i=(x);i<=(y);i++)
#define rf(i,x,y) for(int i=(x);i>=(y);i--)
#define frl(i,x,y) for(int i=(x);i<(y);i++)
using namespace std;
const int N=100005;
struct node{
int v,rnd,s,sz; //s表示权值为v的个数,sz表示子树size,然而我经常忘记s的存在,直接写成1,挂了好久
node* ch[2];
inline int cmp(int x){ return x>v; } //这其实是写旋转treap时留下的历史遗留问题= =无视吧
inline void maintain(){
sz=s;
if (ch[0]!=NULL) sz+=ch[0]->sz; //写指针一定要特别注意对NULL的判断
if (ch[1]!=NULL) sz+=ch[1]->sz;
}
node(){
ch[0]=ch[1]=NULL;
rnd=rand();
}
}nd[N];
int tot;
node* rt;
int n;
void read(int &x){ //读优一开始忘记负数了= =
char ch=getchar();x=0;int w=0;
for(;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') w=1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
if (w) x=-x;
}
inline int sss(node* &o){
return o==NULL?0:o->sz;
}
node* &kth(node* &o,int k){
assert(o!=NULL);
int s=sss(o->ch[0]);
if (s+1<=k&&s+o->s>=k) return o;
if (s+1>k) return kth(o->ch[0],k);
return kth(o->ch[1],k-o->s-s);
}
void split(node* o,node* &L,node* &r,int k){ //split <=k
if (o==NULL) return L=r=NULL,void();
if (o->v<=k){
split(o->ch[1],o->ch[1],r,k);
L=o;
} else{
split(o->ch[0],L,o->ch[0],k);
r=o;
}
o->maintain(); //要经常维护一下信息
}
node* &merge(node* &L,node* &r){
if (L==NULL) return r;
if (r==NULL) return L;
if (L->rnd<r->rnd){
L->ch[1]=merge(L->ch[1],r);
L->maintain();
return L;
} else{
r->ch[0]=merge(L,r->ch[0]);
r->maintain();
return r;
}
}
void add_node(int v){
node* L;
node* r;node* xx;
split(rt,L,r,v);
if (L!=NULL&&(xx=kth(L,L->sz))->v==v){ //如果存在这个数直接加个数
split(L,L,xx,v-1);
xx->s++;xx->sz++; //不要忘记加size
//rt=merge(L,r);
}else{
xx=&nd[++tot];
xx->s=xx->sz=1;xx->v=v;
}
rt=merge(merge(L,xx),r);
}
void del_node(int v){
node *L,*r,*mid;
split(rt,L,r,v-1);
split(r,mid,r,v);
if (mid!=NULL&&mid->s>1) mid->s--,mid->sz--,r=merge(mid,r);
rt=merge(L,r);
}
int rk(node* &o,int v){
assert(o!=NULL);
if (o->v==v) return sss(o->ch[0])+1;
if (v<o->v) return rk(o->ch[0],v);
else return rk(o->ch[1],v)+sss(o->ch[0])+o->s;
}
int rkk(node* rt,int v){
node *L,*r;
split(rt,L,r,v-1);
int ans=sss(L)+1;
rt=merge(L,r);
return ans;
}
//rk和rkk都可以求rank,一个通过split一个通过size,好像rkk更快?感觉有点奇怪...
int main(){
srand(19260817);
read(n);
int tp,x;
node *L,*r;
int s=0;
add_node(19260817);
fr(o,1,n){
read(tp);read(x);
if (tp==1) add_node(x);
if (tp==2) del_node(x);
if (tp==3) printf("%d\n",rk(rt,x)),s++;
if (tp==4) printf("%d\n",kth(rt,x)->v),s++;
if (tp==5){
split(rt,L,r,x-1);
printf("%d\n",kth(L,L->sz)->v),s++;
rt=merge(L,r);
}
if (tp==6){
split(rt,L,r,x);
printf("%d\n",kth(r,1)->v),s++;
rt=merge(L,r);
}
//if (s==670) printf("----%d %d %d\n",o,tp,x);
}
return 0;
}
非旋treap (fhq treap) 指针版的更多相关文章
- 非旋Treap——fhq treap
https://www.luogu.org/problemnew/show/P3369 知识点:1.拆分split,合并merge 2.split,merge要点:通过传址调用来简便代码 3.记得ro ...
- 可持久化Treap(fhq Treap,非旋转式Treap)学习(未完待续)
简介: Treap,一种表现优异的BST 优势: 其较于AVL.红黑树实现简单,浅显易懂 较于Splay常数小,通常用于树套BST表现远远优于Splay 或许有人想说S ...
- 「学习笔记」 FHQ Treap
FHQ Treap FHQ Treap (%%%发明者范浩强年年NOI金牌)是一种神奇的数据结构,也叫非旋Treap,它不像Treap zig zag搞不清楚(所以叫非旋嘛),也不像Splay完全看不 ...
- 2021.12.08 平衡树——FHQ Treap
2021.12.08 平衡树--FHQ Treap http://www.yhzq-blog.cc/fhqtreapzongjie/ https://www.cnblogs.com/zwfymqz/p ...
- 可持久化treap(FHQ treap)
FHQ treap 的整理 treap = tree + heap,即同时满足二叉搜索树和堆的性质. 为了使树尽可能的保证两边的大小平衡,所以有一个key值,使他满足堆得性质,来维护树的平衡,key值 ...
- 非旋 treap 结构体数组版(无指针)详解,有图有真相
非旋 $treap$ (FHQ treap)的简单入门 前置技能 建议在掌握普通 treap 以及 左偏堆(也就是可并堆)食用本blog 原理 以随机数维护平衡,使树高期望为logn级别, FHQ ...
- 非旋(fhq)Treap小记
前置知识:二叉搜索树 以下摘自 ↑: 二叉搜索树每次操作访问O(深度)个节点. 在刻意构造的数据中,树的形态会被卡成一条链,于是复杂度爆炸 它的复杂度与直接暴力删除类似. 但二叉搜索树扩展性强.更复杂 ...
- 关于非旋FHQ Treap的复杂度证明
非旋FHQ Treap复杂度证明(类比快排) a,b都是sort之后的排列(从小到大) 由一个排列a构造一颗BST,由于我们只确定了中序遍历=a,但这显然是不能确定一棵树的形态的. 由一个排列b构造一 ...
- [模板] 平衡树: Splay, 非旋Treap, 替罪羊树
简介 二叉搜索树, 可以维护一个集合/序列, 同时维护节点的 \(size\), 因此可以支持 insert(v), delete(v), kth(p,k), rank(v)等操作. 另外, prev ...
随机推荐
- [经验分享]C# 操作Windows系统计划任务
背景:我做了一个事情是要自己提前创建好很多要定时执行的任务,在我不在的时候自动执行这些程序,以保证我的工作能无人值守,那么我就需要建立系统计划任务来帮我完成这件事情,当然用脑子想想如何实现,很简单,每 ...
- 用深度学习做命名实体识别(七)-CRF介绍
还记得之前介绍过的命名实体识别系列文章吗,可以从句子中提取出人名.地址.公司等实体字段,当时只是简单提到了BERT+CRF模型,BERT已经在上一篇文章中介绍过了,本文将对CRF做一个基本的介绍.本文 ...
- Numpy数组操作
""" Numpy 数组操作 修改数组形状 函数 描述 reshape 不改变数据的条件下修改形状 flat 数组元素迭代器 flatten 返回一份数组拷贝,对拷贝所做 ...
- RRiBbit,一个事件总线.基于spring配置不同服务通信!
1.何为RRiBbit? *一种开源事件总线技术,能够让模块(组件)之间双向通讯,也被称为请求相应总线(request-response-bus),使用简单,相对其他框架来说,RRiBbit只需要加个 ...
- Java的IO操作之关闭流
我们知道,当结束对一个流的操作时,需要调用流的close()方法对其进行释放,这将释放掉与这个流有关的所有资源,包括文件句柄.端口等.如果不关闭流,垃圾回收机制将无法识别你是否已使用完这个文件,读取的 ...
- 蓝牙TWS耳机IBRT的原理初分析
最近在倒腾TWS对耳的一些东西,看到一些源码,发现一个新概念,IBRT没有搞清楚,抱着吾将上下而求索的态度,详细看了一些代码,查了一些资料,还是发现了不少有价值的信息的.至少,我突然感觉自己懂了一些什 ...
- 【C语言笔记】#define与typedef的区别
1.#define define是预处理指令,在编译时不进行任何检查,只进行简单的替换 宏定义的一般形式为: #define 宏名 字符串 这里所说的字符串是一般意义上的字符序列,不要和C语言中的字符 ...
- PHP 利用闭包偷窥马对人类的想法
<?php /** * reference:http://www.php.net/manual/en/reflectionmethod.getclosure.php * Learn this a ...
- [BZOJ1202] [NZOI2005]狡猾的商人
Description 刁姹接到一个任务,为税务部门调查一位商人的账本,看看账本是不是伪造的.账本上记录了n个月以来的收入情况,其中第i 个月的收入额为Ai(i=1,2,3...n-1,n), .当 ...
- VS2017-Linux项目-使用第三方库如何配置
1.虚拟机Ubuntu 16.04,安装第三方库,perftools::tcmalloc. 2.Win10下vs2017创建linux项目. 3.项目>>属性>>VC++ 目录 ...