文章目录
- 前言
- 操作
- 合并
- 分裂
- 插入
- 删除
- 查找第k大
- 查询x的排名
- 前驱后继
- 完整代码
所谓无旋treap,就是不带旋转的treap
前言
现在“理论上”我会四种平衡树了
之前说无旋treap功能弱,是我狗眼看银低了qwq
这玩意区间上该搞的也能搞
而且确实是非常的 好写!!
有点想把这个作为默认项了
呜呜呜朝三暮四肿么办呐
操作
关键是合并和分裂
合并
考虑合并u和v两棵子树
把优先级高的作为根
剩下的接着合并即可
il int merge(int u,int v){if(!u) return v;if(!v) return u;if(tr[u].key>tr[v].key){tr[u].rs=merge(tr[u].rs,v);pushup(u);return u;}else{tr[v].ls=merge(u,tr[v].ls);pushup(v);return v;}
}
分裂
给定一个val
<=val的归一棵,>=val的归另一棵
讨论一些根归谁
然后递归一下即可
如果要求前k个一棵是一个道理
il void split(int x,int v,int &L,int &R){if(!x){L=R=0;return;}if(tr[x].val<=v){L=x;split(tr[L].rs,v,tr[L].rs,R);pushup(L);}else{R=x;split(tr[R].ls,v,L,tr[R].ls);pushup(R);}return;
}
插入
插入一个为v的元素
把树按照v掰成两个
把开的新点merge上去即可
il void ins(int v){int a(0),b(0),c(0);split(r,v,a,b);c=New(v);r=merge(merge(a,c),b);return;
}
删除
删除一个v
先把<=v的split出来
再把<v的split出来
剩下的全是=v的
把其左右子树合并就相当于扣掉一个
最后merge回去就行
il void del(int v){int a(0),b(0),c(0);split(r,v,a,b);split(a,v-1,a,c);r=merge(merge(a,merge(tr[c].ls,tr[c].rs)),b);
}
查找第k大
BST常规操作
il int findnth(int kth){//printf("findnth:%d\n",kth);int x=r;while(1){//printf("x=%d val=%d siz=%d ls=%d rs=%d\n",x,tr[x].val,tr[x].siz,tr[x].ls,tr[x].rs);if(kth<=tr[tr[x].ls].siz) x=tr[x].ls;else if(kth==tr[tr[x].ls].siz+1) return tr[x].val;else{kth-=tr[tr[x].ls].siz+1;x=tr[x].rs;}}
}
查询x的排名
这个用常规的BST的操作是 不行 的!
因为树上存在这权值相同的点
但可以直接把<x的split出来查询siz
也很方便
最后记得要merge回去!
il int findrnk(int v){int a(0),b(0),c(0),res;split(r,v-1,a,b);res=tr[a].siz;r=merge(a,b);return res+1;
}
前驱后继
BST典中典了属于是
findnth(findrnk(x)-1)//前驱
findnth(findrnk(x+1))//后继
完整代码
当然是普通平衡树啦
#include<bits/stdc++.h>
#define ll long long
#define il inline
using namespace std;
const int N=1e6+100;
const int M=2e6+100;
ll read(){ll x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-') f=-1;c=getchar();};while(isdigit(c)){x=x*10+c-'0';c=getchar();}return x*f;
}
int n,m,s,t;
struct node{int ls,rs,val,siz,key;
}tr[N<<2];
int r,tot;
il int New(int v){++tot;tr[tot].siz=1;tr[tot].ls=tr[tot].rs=0;tr[tot].key=rand();tr[tot].val=v;return tot;
}
il void pushup(int x){tr[x].siz=tr[tr[x].ls].siz+tr[tr[x].rs].siz+1;return;
}
il int merge(int u,int v){if(!u) return v;if(!v) return u;if(tr[u].key>tr[v].key){tr[u].rs=merge(tr[u].rs,v);pushup(u);return u;}else{tr[v].ls=merge(u,tr[v].ls);pushup(v);return v;}
}
il void split(int x,int v,int &L,int &R){if(!x){L=R=0;return;}if(tr[x].val<=v){L=x;split(tr[L].rs,v,tr[L].rs,R);pushup(L);}else{R=x;split(tr[R].ls,v,L,tr[R].ls);pushup(R);}return;
}
il int findnth(int kth){//printf("findnth:%d\n",kth);int x=r;while(1){//printf("x=%d val=%d siz=%d ls=%d rs=%d\n",x,tr[x].val,tr[x].siz,tr[x].ls,tr[x].rs);if(kth<=tr[tr[x].ls].siz) x=tr[x].ls;else if(kth==tr[tr[x].ls].siz+1) return tr[x].val;else{kth-=tr[tr[x].ls].siz+1;x=tr[x].rs;}}
}
il int findrnk(int v){int a(0),b(0),c(0),res;split(r,v-1,a,b);res=tr[a].siz;r=merge(a,b);return res+1;
}
il void ins(int v){int a(0),b(0),c(0);split(r,v,a,b);c=New(v);r=merge(merge(a,c),b);return;
}
il void del(int v){int a(0),b(0),c(0);split(r,v,a,b);split(a,v-1,a,c);r=merge(merge(a,merge(tr[c].ls,tr[c].rs)),b);
}
int main(){n=read();for(int i=1;i<=n;i++){int op=read(),x=read();switch(op){case 1:{ins(x);break;}case 2:{del(x);break;}case 3:{printf("%d\n",findrnk(x));break;}case 4:{printf("%d\n",findnth(x));break;}case 5:{printf("%d\n",findnth(findrnk(x)-1));break;}case 6:{printf("%d\n",findnth(findrnk(x+1)));break;}}}return 0;
}
/*
*/
thanks for reading!