无旋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的完美讲解

posted @ 2017-10-06 20:19  Hzoi_QTY  阅读(206)  评论(0编辑  收藏  举报