无旋Treap
想要搞带区间的平衡树,要么用splay,要么用无旋treap。(现在只会后面的)
先%一下大佬LadyLex
无旋treap简言之不再有左旋和右旋,而多了拆分子树和合并子树的过程。
slipt为拆树。D 为定义的pair,first是拆下来的树,second是拆下来后剩下的原树。
如果要拆下来的树的大小比左子树小,就拆左子树,并把拆完的树接回来。
如果左子树不够大,就要连上根和右子树,把拆下来的树接在原树上->要拆的树,剩下的树就是“拆剩下的原树”
D split(treap *f,int k) { if(f==null)return D(null,null); push(f);D y; if(f->ch[0]->size>=k) {y=split(f->ch[0],k);f->ch[0]=y.second;f->update();y.second=f;} else {y=split(f->ch[1],k-f->ch[0]->size-1);f->ch[1]=y.first;f->update();y.first=f;} return y; }merge为合并树。因为维护的树根节点的id值最小(我这么维护的)a树的值要比b树的小。
如果a的id小,把b接为a的右子树,反之,把a接为b的左子树。
treap* merge(treap *a,treap *b) { if(a==null)return b; if(b==null)return a; push(a);push(b); if(a->id<b->id) {a->ch[1]=merge(a->ch[1],b);a->update();return a;} else {b->ch[0]=merge(a,b->ch[0]);b->update();return b;} }
这个只是点的修改,如果为区间,加一个类似线段树的延迟标记,记录当前节点是否更改。
插入值
inline void Insert(int v) { int k=Getkth(root,v); D x=Split(root,k); Treap *o=new Treap(v); root=Merge(Merge(x.first,o),x.second); }删除值
void Delete(int v) { int k=Getkth(root,v); D x=Split(root,k); D y=Split(x.second,1); root=Merge(x.first,y.second); }获得此点的排名
int Getkth(Treap *o,int v) { if(o==NULL)return 0; return(o->val>=v)?Getkth(o->ch[0],v):Getkth(o->ch[1],v)+size(o->ch[0])+1; }
求某点的权值
inline int get_val(int rank) { D x=split(root,rank-1); D y=split(x.second,1); int ans=y.first->h; root=merge(merge(x.first,y.first),y.second); return ans; }
我说的并不是太明白,链接一下LadyLex的完美讲解