Splay
伸展树的作用和非旋转Treap类似,只不过它依然通过旋转来维持平衡,双旋的情况稍微复杂一点(单旋无法保证均摊\(O(logn)\)),主要有三种操作:
- splay(k):将第k大元素旋转至根节点
- merge(x,y):合并两棵splay,返回新的根节点
- split(x,k):将元素[1,k]和[k+1,n]分离,返回两棵新树的根节点
其他维护操作可以用标记完成,建树直接二分。
代码:
struct Node{
Node *ch[2];
int v,size,flip;
Node(int val,Node *null) {v=val,size=1,flip=0,ch[0]=ch[1]=null;}
int cmp(int k)
{
if ((ch[0]->size+1)==k) return -1;
return ((ch[0]->size+1)<k)?(1):(0);
}
void maintain() {size=ch[0]->size+ch[1]->size+1;}
void pushdown() {if (flip) swap(ch[0],ch[1]),ch[0]->flip^=1,ch[1]->flip^=1,flip=0;}
} *null,*root;
//-------------------------------------
Node *newnode(int v) {return new Node(v,null);}
Node* rotate(Node* &o,int d)
{
Node* k=o->ch[d^1];o->ch[d^1]=k->ch[d],k->ch[d]=o;
o->maintain(),k->maintain(),o=k;
}
void splay(Node* &o,int k)
{
o->pushdown();int d=o->cmp(k);
if (d==1) k-=o->ch[0]->size+1;
if (d!=-1)
{
Node* p=o->ch[d];p->pushdown();
int d2=p->cmp(k),k2=(d2==0)?(k):(k-p->ch[0]->size-1);
if (d2!=-1)
{
splay(p->ch[d2],k2);
if (d==d2) rotate(o,d^1); else rotate(p,d2^1);
}
rotate(o,d^1);
}
}
Node* merge(Node *x,Node *y)
{
if (x==null) return y;
splay(x,x->size);
x->ch[1]=y,x->maintain();
return x;
}
Node* split(Node *o,int k,Node* &l,Node* &r)
{
splay(o,k);
if (o->flip)`
o->pushdown();
l=o,r=o->ch[1],o->ch[1]=null,l->maintain();
}
Splay 2.0
我们在splay上加上维护父节点与tag,可以做到额外的一些操作:
- rank(x):对于一个已知指针的结点,查出其在Splay中的是第几位。
- sum/min/maxi(x,l,r):查找给定的Splay树x,区间\([l,r]\)的返回值。
代码:
struct Node{
Node *ch[2],*f;
int v,size;
LL s,sum,tag; //当前结点值,维护值,标记,
Node(int val,Node *null) {v=val,s=0,sum=0,size=1,tag=0,ch[0]=ch[1]=f=null;}
void maintain()
{
size=ch[0]->size+ch[1]->size+1;
sum=ch[0]->sum+ch[1]->sum+s; //维护当前维护值
}
void pushdown() //下放结点,类似于线段树的更新方式
{
if (tag) ch[0]->update(tag),ch[1]->update(tag),tag=0;
}
void update(LL val) //维护结点(tag值在下次访问再下放)
{
s+=val,sum+=(LL)(size)*val;
if (size>1) tag+=val;
}
int cmp(int k)
{
if ((ch[0]->size+1)==k) return -1;
return (ch[0]->size>=k)?(0):(1);
}
} *root,*null;
Node *newnode(int v) {return new Node(v,null);}
//-----------------------------
Node *rotate(Node* &o,int d)
{
Node* k=o->ch[d^1];
o->ch[d^1]=k->ch[d],o->ch[d^1]->f=o; //rotate需要维护父节点
k->ch[d]=o,o->f=k;
o->maintain(),k->maintain();o=k;
}
void splay(Node* &o,int k)
{
o->pushdown();int d=o->cmp(k); //先下放
if (d==1) k-=o->ch[0]->size+1;
if (d!=-1)
{
Node* p=o->ch[d];p->pushdown();
int d2=p->cmp(k),k2=(d2==0)?(k):(k-p->ch[0]->size-1);
if (d2!=-1)
{
splay(p->ch[d2],k2);
if (d==d2) rotate(o,d^1); else rotate(o->ch[d],d);
}
rotate(o,d^1);
}
}
Node* merge(Node *x,Node *y)
{
if (x==null) return y;
if (y==null) return x;
splay(x,x->size);
x->ch[1]=y,y->f=x,x->maintain(); //维护父节点
return x;
}
void split(Node *o,int k,Node* &l,Node* &r)
{
if (k<=0) {l=null,r=o;return;}
splay(o,k);
l=o,r=o->ch[1],l->f=r->f=null,o->ch[1]=null,l->maintain(); //记得清空父节点
}
void rnk(Node *o,int &ans,int d) //调用时 ans=0,d=1
{
if (o==null) return;
if (d==1) ans+=o->ch[0]->size+1;
rnk(o->f,ans,(o->f->ch[0]==o)?(0):(1));
}

浙公网安备 33010602011771号