无旋 treap 学习
原理
前言
- t r e a p = t r e e + h e a p treap=tree+heap treap=tree+heap,其在 BST (二叉搜索树) 的基础上,多添加了一个参数 key ,通过维护 key 的二叉堆性质,来使得 t r e a p treap treap 的期望高度达到 l o g n logn logn
- 核心: s p l i t split split 和 m e r g e merge merge 。通过 s p l i t split split 将一棵 t r e a p treap treap 拆分成一棵值均 < = v a l <=val <=val 的 t r e a p treap treap 和一棵值均 > = v a l >=val >=val 的 t r e a p treap treap 。通过 m e r g e merge merge 将分好的两棵 t r e a p treap treap 合并成一棵具有二叉堆性质的二叉搜索树。
split
void split(int now,int &a,int &b,int val) {
if(now==0) {
a=b=0;
return;
}
if(tr[now].val<=val)a=now,split(tr[now].r,tr[a].r,r,val);
else b=now,split(tr[now].l,a,tr[b].l,val);
pushup(now);
}
merge
void merge(int &now,int a,int b) {//把已 a 为根的树和已 b 为根的树合并为以 now 为根的树
if(a==0||b==0) {
now=a+b;
return;
}
if(tr[a].val>tr[b].val)now=a,merge(tr[now].r,tr[a].r,r);
else now=b,merge(tr[now].l,a,tr[b].l);
pushup(now);
}
维护数值模板
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct Treap {
int root,cnt;
struct node {
int val,key,l,r,size;
} tr[N];
Treap() {
root=cnt=0;
}
void pushup(int now) {
tr[now].size=tr[tr[now].l].size+tr[tr[now].r].size+1;
}
int newnode(int val) {
tr[++cnt].val=val;
tr[cnt].l=tr[cnt].r=0;
tr[cnt].size=1;
tr[cnt].key=rand();
return cnt;
}
void split(int now,int &a,int &b,int val) {
if(now==0) {
a=b=0;
return;
}
if(tr[now].val<=val)a=now,split(tr[now].r,tr[a].r,b,val);
else b=now,split(tr[now].l,a,tr[b].l,val);
pushup(now);
}
void merge(int &now,int a,int b) {//把已 a 为根的树和已 b 为根的树合并为以 now 为根的树
if(a==0||b==0) {
now=a+b;
return;
}
if(tr[a].key>tr[b].key)now=a,merge(tr[now].r,tr[a].r,b);
else now=b,merge(tr[now].l,a,tr[b].l);
pushup(now);
}
void insert(int val) {
int x=0,y=0;
split(root,x,y,val-1);
merge(x,x,newnode(val));
merge(root,x,y);
}
void del(int val) {
int x=0,y=0,z=0;
split(root,x,y,val);
split(x,x,z,val-1);
merge(z,tr[z].l,tr[z].r);
merge(x,x,z);
merge(root,x,y);
}
int rnk(int val) {
int x=0,y=0;
split(root,x,y,val-1);
int ans=tr[x].size+1;
merge(root,x,y);
return ans;
}
int kth(int k) {
int now=root;
while(1) {
if(k==tr[tr[now].l].size+1)return tr[now].val;
if(k<=tr[tr[now].l].size)now=tr[now].l;
else k-=tr[tr[now].l].size+1,now=tr[now].r;
}
}
int pre(int val) {
int x=0,y=0;
split(root,x,y,val-1);
int ans=tr[x].val;
merge(root,x,y);
return ans;
}
int suf(int val) {
int x=0,y=0;
split(root,x,y,val);
int size=tr[x].size+1;
merge(root,x,y);
return kth(size);
}
};
维护序列,动态数组模板
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct Treap {
int root,cnt;
struct node {
int val,key,l,r,size,tag;
} tr[N];
Treap() {
root=cnt=0;
}
void pushup(int now) {
tr[now].size=tr[tr[now].l].size+tr[tr[now].r].size+1;
}
void pushdown(int now){
if(tr[now].tag){
swap(tr[now].l,tr[now].r);
tr[now].tag^=1;
if(tr[now].l)tr[tr[now].l].tag^=1;
if(tr[now].r)tr[tr[now].r].tag^=1;
}
}
int newnode(int val) {
tr[++cnt].val=val;
tr[cnt].l=tr[cnt].r=tr[cnt].tag=0;
tr[cnt].size=1;
tr[cnt].key=rand();
return cnt;
}
void split(int now,int &a,int &b,int x) {//维护序列问题用这个,分出来的第 1 棵树切好有 x 个结点
if(now==0) {
a=b=0;
return;
}
pushdown(now);
if(tr[tr[now].l].size+1<=x)a=now,split(tr[now].r,tr[a].r,b,x-tr[tr[now].l].size-1);
else b=now,split(tr[now].l,a,tr[b].l,x);
pushup(now);
}
void merge(int &now,int a,int b) {//把已 a 为根的树和已 b 为根的树合并为以 now 为根的树
if(a==0||b==0) {
now=a+b;
return;
}
pushdown(a);
pushdown(b);
if(tr[a].key>tr[b].key)now=a,merge(tr[now].r,tr[a].r,b);
else now=b,merge(tr[now].l,a,tr[b].l);
pushup(now);
}
void insert(int pos,int val) {//在第 pos 个位置后面插入一个元素 val
int x=0,y=0;
split(root,x,y,pos);
merge(x,x,newnode(val));
merge(root,x,y);
}
void del(int pos) {//删除第 pos 个位置
int x=0,y=0,z=0;
split(root,x,y,pos);
split(x,x,z,pos-1);
merge(root,x,y);
}
int operator[] (int pos){
int x=0,y=0,z=0;
split(root,x,y,pos);
split(x,x,z,pos-1);
int ans=tr[z].val;
merge(x,x,z);
merge(root,x,y);
return ans;
}
void write(int now){
if(now==0)return;
write(tr[now].l);
cout<<tr[now].val<<" ";
write(tr[now].r);
}
void write(){
write(root);
}
void reserve(int l,int r){
int x=0,y=0,z=0;
split(root,x,y,l-1);
split(y,y,z,r-l+1);
tr[y].tag^=1;
merge(y,y,z);
merge(root,x,y);
}
void gonext(int l,int r){
int x=0,y=0,z=0,t=0;
split(root,x,y,l-1);
split(y,y,z,r-l);
split(z,z,t,1);
//[1,l-1],[l,r-1],[r,r],[r+1,n]
merge(y,y,t);
merge(z,z,y);
merge(root,x,z);
}
} tr;