Treap树堆非旋转算法
核心操作:分裂与合并
1.分裂(split)有两种:按权值分裂与按位置(排名)分裂
如果按权值分裂(split):那么分出来两棵树的第一棵树上的每个数的大小都小于(或者小于等于,视具体情况)x。
如果按位置分裂(split):那么分出来两棵树的第一棵树上恰好有x个结点。
//按权值分裂
inline void split(int k,int &l,int &r,int x)
{//将以k为根的树按权值x分成两棵树分别以l为根(小于x),以r为根(不小于x)
if(!k){//分裂到底了,返回
l=r=0;
return ;
}
if(tree[k].val<x){//如果比它小
l=k;//那么x肯定在k的右子树里,先将k贴到第一个答案,
split(tree[l].r,tree[l].r,r,x);//再将第一个棵答案的右子树按x分开得到答案
}else{//反之亦然
r=k;
split(tree[r].l,l,tree[r].l,x};
}
push_up(k);
}
//同理可得近位置分裂
inline void split(int k,int &l,int *r,int x)
{ if(!k){
l=r=0;
return ;
}
if(tree[tree[k].l].size+1<=x){
l=k;
split(tree[l].r,tree[l].r,r,x-tree[tree[k].l].size-1);
}else{
r=k;
split(tree[r].l,l,tree[r].l,x);
}
push_up(k);
}
2.合并操作
inline void merge(int &k,int l,int r)
{//以l为根的树(权值小于以r为根的权值)和以r为根的树合并到以k为根的树
if(!l||!r){
k=l+r;
return ;
}
if(tree[l].p>tree[r].p){//默认为大根堆
k=l;
merge(tree[k].r,tree[k].r,r);
else{
k=r;
merge(tree[k].l,l,tree[k].l);
}
push_up(k);
}
3.插入操作
inline void insert(int val){
int x,y;
split(root,x,y,val);//按val分裂后x树的值小于val,y树的值不小于val
merge(x,x,New(val));
merge(root,x,y);
}
4.删除操作
inline void Delete(int val){
int x,y,z;
split(root,x,y,val+1);
split(x,x,z,val);
merge(z,tree[z].l,tree[z].r);
merge(x,x,z);
merge(root,x,y);
}
5.x的排名
inline int rnk(int val){
int x,y;
split(root,x,y,val);
int ans=tree[x].size+1;
merge(root,x,y);
return ans;
}
6.x的前驱
inline int pre(int val){
int x,y;
split(root,x,y,val);
int z;
z=x;
while(tree[z].r!=0) z=tree[z].r;//x树中的最大值
int ans=tree[z].val;
merge(root,x,y);
return ans;
}
7.x的后续
inline int suf(int val){
int x,y;
split(root,x,y,val+1);
int z;
z=y;
while(tree[z].l!=0) z=tree[z].l;//y树的最小值
int ans=tree[z].val;
merge(root,x,y);
return ans;
}
8.更新
inline void push_up(int k){
tree[k].size=tree[tree[k].l].size+tree[tree[k].r].size+1;
}
9.新建结点
inline int New(int val){
tree[++cnt].val=val;
tree[cnt].l=tree[cnt].r=0;
tree[cnt].size=1;
return cnt;
}
10.数据类型
const int maxn=100010;
struct node{
int val;
int p;
int size;
int l;
int r;
} tree[maxn];
int cnt,root;
//非旋转 数组版
#include<bits/stdc++.h>
using namespace std;
const int maxn=1000000;
struct node{
int val;
int size;
int p;
int l;
int r;
}tree[maxn];
int root,cnt;
inline void push_up(int k)
{
tree[k].size=tree[tree[k].l].size+tree[tree[k].r].size+1;
}
inline void split(int k,int &l,int &r,int x)
{
if (!k)
{
l=r=0;
return ;
}
if (tree[k].val<x)
{
l=k;
split(tree[l].r,tree[l].r,r,x);
}
else
{
r=k;
split(tree[r].l,l,tree[r].l,x);
}
push_up(k);
}
inline void merge(int &k,int l,int r)
{
if(!l||!r)
{
k=l+r;
return ;
}
if (tree[l].p>tree[r].p)
{
k=l;
merge(tree[k].r,tree[k].r,r);
}
else
{
k=r;
merge(tree[k].l,l,tree[k].l);
}
push_up(k);
}
int New(int val)
{
tree[++cnt].val=val;
tree[cnt].r=tree[cnt].l=0;
tree[cnt].size=1;
tree[cnt].p=rand();
return cnt;
}
inline void insert(int val)
{
int x,y;
split(root,x,y,val);
merge(x,x,New(val));
merge(root,x,y);
}
inline void Delete(int val)
{
int x,y,z;
split(root,x,y,val+1);
split(x,x,z,val);
merge(z,tree[z].l,tree[z].r);
merge(x,x,z);
merge(root,x,y);
}
inline int rnk(int val)
{
int x,y;
split(root,x,y,val);
int ans=tree[x].size+1;
merge(root,x,y);
return ans;
}
inline int kth(int k)
{
int x=root;
while(true)
{
if (k==tree[tree[x].l].size+1) return tree[x].val;
if (k<=tree[tree[x].l].size) x=tree[x].l;
else
{
k-=tree[tree[x].l].size+1;
x=tree[x].r;
}
}
}
inline int pre(int val)
{
int x,y,z;
split(root,x,y,val);
z=x;
while(tree[z].r!=0)
{
z=tree[z].r;
}
int ans=tree[z].val;
merge(root,x,y);
return ans;
}
inline int suf(int val)
{
int x,y;
split(root,x,y,val+1);
int z;
z=y;
while(tree[z].l!=0)
{
z=tree[z].l;
}
int ans=tree[z].val;
merge(root,x,y);
return ans;
}
int main()
{
int n;
cin>>n;
while(n--)
{
int op,x;
cin>>op;
if (op==1)
{
cin>>x;
insert(x);
}
else if(op==2)
{
cin>>x;
Delete(x);
}
else if(op==3)
{
cin>>x;
cout<<rnk(x)<<endl;
}
else if(op==4)
{
cin>>x;
cout<<kth(x)<<endl;
}
else if(op==5)
{
cin>>x;
cout<<pre(x)<<endl;
}
else
{
cin>>x;
cout<<suf(x)<<endl;
}
}
}
浙公网安备 33010602011771号