最近开始学习平衡树,在学长的强烈推荐下学习了AVL、红黑树、splay(以上我都还没学)treap。
首先讲一下个人对treap(树堆)的理解。
treap,顾名思义,就是tree+heap,首先因为treap是一棵平衡树,因此它满足二叉排序树的性质,接下来,为了防止BST退化成一条链,它使用了随机化的方式给每个点分布一个优先级,然后要求优先级满足堆的性质,但不必是一棵完全二叉树,这样的效率期望就是每次基础操作( log n )的。
然后简单讲一下树堆的基础操作,代码参见例题与AC代码。
1.插入 平衡树最基础的操作之一就是插入一个新节点,首先我们按照BST的性质插入这个节点,接下来按照优先级进行旋转维护堆的性质,这样就可以了。
2.删除 平衡树最基础的操作之二就是删除一个原有节点,同样的我们按照BST的性质找到这个节点,然后按照BST的方法删除它,接下来维护堆的性质即可。
3.查找 平衡树最基础的操作之三就是查找,一般主要包含2种查找:1)给定一个权值,查找排名 2)给定一个排名,查找权值 这2种操作是大同小异的,都只需要按照BST的性质来进行即可。
下面是本题题解。
题目就是平衡树最基础的操作裸题,所以就直接参考上面所说的以及代码就好了。(1912KB 232ms on BZOJ)
#include <stdio.h> #define getchar() (S==TT&&(TT=(S=BB)+fread(BB,1,1<<15,stdin),S==TT)?EOF:*S++) char BB[1<<15],*TT=BB,*S=BB; inline int read(){ int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9') f=ch=='-'?-1:1,ch=getchar(); while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*f; } inline int rad(){ static int x=23333; x^=x<<13,x^=x>>17,x^=x<<5;return x; } struct treap{ treap *ls,*rs; int val,pri,cnt,sz; treap(int val):val(val){ls=rs=NULL,cnt=sz=1,pri=rad();} void combine(){sz=cnt;if (ls!=NULL) sz+=ls->sz;if (rs!=NULL) sz+=rs->sz;} }*root; inline void lrotate(treap* &x){treap *y=x->rs;x->rs=y->ls;y->ls=x;y->sz=x->sz;x->combine();x=y;} inline void rrotate(treap* &x){treap *y=x->ls;x->ls=y->rs;y->rs=x;y->sz=x->sz;x->combine();x=y;} inline void Insert(treap* &x,int val){ if (x==NULL){x=new treap(val); return;} if (val==x->val) x->cnt++; else if (val>x->val){Insert(x->rs,val);if (x->rs->pri<x->pri) lrotate(x);} else {Insert(x->ls,val);if (x->ls->pri<x->pri) rrotate(x);}x->combine(); } void Delete(treap *&x,int val){ if (x==NULL) return; if (val==x->val){ if (x->cnt>1) x->cnt--,x->sz--; else if (x->ls==NULL||x->rs==NULL){ treap *t=x; if (x->ls==NULL) x=x->rs; else x=x->ls; delete t; } else if (x->ls->pri<x->rs->pri) rrotate(x),Delete(x,val); else lrotate(x),Delete(x,val); } else if (val<x->val) x->sz--,Delete(x->ls,val); else x->sz--,Delete(x->rs,val); } inline int find(treap *x,int val){ if (x==NULL) return 0; if (x->ls==NULL){ if (val==x->val) return 1; if (val>x->val) return find(x->rs,val)+x->cnt; return 0; } if (val==x->val)return x->ls->sz+1; if (val<x->val) return find(x->ls,val); return find(x->rs,val)+x->ls->sz+x->cnt; } inline int find_rank(treap *x,int k){ if (x==NULL) return 0; if (x->ls==NULL){ if (k<=x->cnt) return x->val; else return find_rank(x->rs,k-x->cnt); } if (k<=x->ls->sz) return find_rank(x->ls,k); if (k>x->ls->sz+x->cnt) return find_rank(x->rs,k-x->ls->sz-x->cnt); return x->val; } int find_pre(treap *x,int val,int ans){ if (x==NULL) return ans; if (val>x->val) return find_pre(x->rs,val,x->val); return find_pre(x->ls,val,ans); } int find_nxt(treap *x,int val,int ans){ if (x==NULL) return ans; if (val<x->val) return find_nxt(x->ls,val,x->val); return find_nxt(x->rs,val,ans); } int main(){ int q=read(); while (q--){ int opt=read(),x=read(); switch (opt){ case 1:Insert(root,x); break; case 2:Delete(root,x); break; case 3:printf("%d ",find(root,x)); break; case 4:printf("%d ",find_rank(root,x)); break; case 5:printf("%d ",find_pre(root,x,-1)); break; case 6:printf("%d ",find_nxt(root,x,-1)); break; } } }