想要搞带区间的平衡树,要么用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->idid)
{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的完美讲解