目的
普通的二叉搜索树容易退化成一条链,使查询的复杂度从O(logn)变为O(n),所以使用随机数 数组辅助使其不易退化
性质
1:val数组满足二叉搜索树的性质,即左子树内所有节点的val值小于根节点的val,右子树内的所有节点的val值大于根节点的val值(val数组内存的是题目中给出的要放进去的值);
2:key数组满足小(大)根堆的性质,即所有子树的key值小(大)于根节点的key值;
作用
查找前驱,后继;动态加点,删点;动态维护一个有序数集;
操作:
基本操作有
右旋:(因为key值不满足小(大)根堆的特性)将这个节点的左儿子旋到这个节点的位置,
设此节点为p,其左儿子为ls;
因为val[ls]<val[p](性质一)
所以在将ls旋到p的位置这个过程中为了维护性质一,让p成为ls的右儿子,而ls原本的右儿子,设其为 x,因为val[x]<val[p](性质一)且key[x]<key[p](性质二),而此时p的左儿子的为空(因为p的左儿子成了p的父亲节点)所以将x变成p的左儿子;
左旋 :(因为key值不满足小(大)根堆的特性)将这个节点的右儿子旋到这个节点的位置(操作原理同上)
模板 (前驱,后继,第k大值,某数的排名)
#include<bits/stdc++.h> using namespace std; #define ll long long void FRE(){freopen(".in","r",stdin);freopen(".out","w",stdout);} void FCL(){fclose(stdin);fclose(stdout);} inline ll rd() { ll x=0,ert=1;char lk=getchar(); while(!isdigit(lk)){if(lk=='-') ert=-1;lk=getchar();} while(isdigit(lk)){x=(x<<3)+(x<<1)+(lk-'0');lk=getchar();} return x*ert; } const int N=1e5+10,inf=1e9; int ls[N],rs[N],val[N],sz[N],cn[N],cnt,ra[N],rt; void up(int p){sz[p]=sz[ls[p]]+sz[rs[p]]+cn[p];} void ltu(int &p){int t=ls[p];ls[p]=rs[t];rs[t]=p;p=t;up(rs[p]);up(p);} void rtu(int &p){int t=rs[p];rs[p]=ls[t];ls[t]=p;p=t;up(ls[p]);up(p);} void ins(int &p,int x) { if(!p){p=++cnt;val[p]=x;sz[p]=1;cn[p]=1;ra[p]=rand();return ;} if(val[p]==x){cn[p]++;sz[p]++;return ;} if(x<val[p]) {ins(ls[p],x);if(ra[ls[p]]<ra[p]) ltu(p);up(p);} else {ins(rs[p],x);if(ra[rs[p]]<ra[p]) rtu(p);up(p);} return ; } void del(int &p,int x) { if(p==0) return ; if(val[p]==x) { if(cn[p]>1){cn[p]--;sz[p]--;return ;} else if(!ls[p]||!rs[p]) {p=ls[p]+rs[p];return ;} else if(ra[ls[p]]<ra[rs[p]]) ltu(p),del(p,x); else rtu(p),del(p,x);return ; } sz[p]--; x<val[p]?del(ls[p],x):del(rs[p],x); } int rak(int p,int x) { if(!p) return 0; if(val[p]==x) return sz[ls[p]]+1; return x<val[p]?rak(ls[p],x):rak(rs[p],x)+sz[ls[p]]+cn[p]; } int num(int p,int x) { if(!p) return inf; if(x<=sz[ls[p]]) return num(ls[p],x); if((x-sz[ls[p]])<=cn[p]) return val[p]; return num(rs[p],x-sz[ls[p]]-cn[p]); } int pre(int p,int x) { if(!p) return -inf; return val[p]<x?max(val[p],pre(rs[p],x)):pre(ls[p],x); } int nxt(int p,int x) { if(!p) return inf; return val[p]>x?min(val[p],nxt(ls[p],x)):nxt(rs[p],x); } int main() { int n=rd(); for(int i=1;i<=n;i++) { int opt=rd(),x=rd(); switch(opt) { case 1:ins(rt,x);break; case 2:del(rt,x);break; case 3:printf("%d ",rak(rt,x));break; case 4:printf("%d ",num(rt,x));break; case 5:printf("%d ",pre(rt,x));break; case 6:printf("%d ",nxt(rt,x));break; } } return 0; }