最强平衡树——Treap[以我的最弱击败你的最强]

仆の最弱を以て,君の最强を打ち破る。!!——Treap

本人蒟蒻,在平衡树坑中深陷数年。为了早日逃离此天坑,特作此文。

什么是平衡树?度娘传送门
什么是treap?ACdreamers%%%
注:本篇所有代码都在片尾!!(醒目)

CMP

那么了解了这些,我们先列出一个list

NAME 优势 劣势
splay LCT,序列之王 常数大,代码量稍大
RBT 自适应深度平衡树,速度在同类BST中遥遥领先 代码量大
SBT 代码简短,速度快,(退化版很好写) 功能平平,(退化版会被人字梯数据卡掉)

大体上来说,treap的敌人多为这三类。我们逆着证明treap是最强的。

TREAP VS SBT

就以常数来说,sbt与treap的常数皆为12左右,当然以数学证明的 (logn) sbt的常数肯定要比用期望 (logn) 的treap要稳很多,但是就我们平时直观所感觉的速度差,大多是因为rand()调用太耗时,所以解决此问题可以这样

inline int random(){
    static int seed=703; //seed可以随便取
    return seed=int(seed*48271LL%2147483647);
}

以数学的方法快速取得rand值 相关链接

这样一来比较不加读优,sbt为260ms+,treap为360ms+,速度已经很相近了。。。并且由于treap比sbt多一个rd数组存rand值,能有70%左右的速度已经非常可观了,但这不是重点。

Treap真正能够超越sbt的在于可以快速分裂与合并,这是sbt很难做到的,而且一旦去做,就必定会加入Father指针,这样会拖慢sbt旋转的速度。
详见代码 HERE

TREAP VS RBT

这可能是treap最大的敌人,速度足够碾压刚刚还得瑟的SBT(cqf的论文中虽然号称比AVL快[实际情况我还没有试过],但是不敢说比RBT快),STL中set,map这些常用类型的底层实现方式。
这就是让人恐惧并无法自拔(?)的RBT(红黑树)!!
那么这么强大的平衡树,为什么区区一介treap敢于挑战?
在与。。。还记得我对RBT的描述吗?深度平衡树
那么就用你的优势成为你失败的伏笔!!!
引出重量级

重量平衡树与后缀平衡树 丽洁姐的论文

可以发现能够支撑起平衡树向字符串领域进军的,就是treap!!
复杂度在加入了一个类似于线段树的结构后并没有改变 (logn) 呢!暂且不论跳表的普及型以及删除时的恶心程度,一般非确定型跳表的空间复杂的是高于树形结构的BST的,其次跳表根本不是主流吧!!然后替罪羊树比起treap来说要难写一点(毕竟要重建笛卡尔树。。)
综上,treap可以完成许多深度平衡树(AVL、RBT)(SBT算什么?)无法做到的效果。

TREAP VS SPLAY

首先分裂与合并已经在讨论sbt时解决了,再者splay的常数又是在平衡数中排得上名号的(大根堆),单旋spaly直接被链式数据卡死,所以splay只有在序列与LCT上称王称霸。LCT有关
但真的是这样吗?
谈谈Treap与LCT,既然都能不旋转来分裂合并了,那么LCT自然是手到擒来。LCT例子
CDQZ本部的几个大神就是LCT只打treap。
所以splay能得瑟的就是序列之王这个名号了!
光速打脸 NOI2005 维护数列
呵呵,虽然分裂合并式的Treap,速度慢,但是代码很好写,毕竟靠随机值无脑合并分裂啊。

结论(彩蛋?)

的确,treap在速度上输给了sbt、rbt(远远地),代码量上也仅仅与sbt持平(基础部分不到40行),分裂合并的常数值也比splay大。。
(观众:好像一无是处耶?)
但是treap反向证明了它自己可以做到那么多不同平衡树自己独具特点的功能,就好比金庸集各家之大成,虽未超越,但单单地将其聚合起来也足以称王了。
从重量平衡引申出的后缀平衡树,非旋转式引出分裂与合并,treap很弱,因为它不完整(从定义上就不完整),但也正是如此他对于OIer来说不是如RBT般的神,splay般的功能强大,sbt般的简洁飞速,所以它需要成长,对于没一点常数的争取,对于自身结构的改变,以及。。。。。本文最后的彩蛋!!

可持久化平衡树

这是多少OIer在可持久化treap发明前学平衡树的心结,那么强大的平衡树为什么没有能简单可持久化的方式呢?直到可持久化treap横空出世,震惊全球(夸张。),多少代OIer的愿望通过treap残缺的美在此得以实现。

code

普普通通的treap——rand()优化后

bzoj3224 普通平衡树

#include
#include
#include
using namespace std;
struct data{
    int l,r,v,size,rnd,w;
}tr[100005];
int n,size,root,ans;
inline int randad(){
    static int seed=703; //seed可以随便取
    return seed=int(seed*48271LL%2147483647);
}
void update(int k)//更新结点信息
{
    tr[k].size=tr[tr[k].l].size+tr[tr[k].r].size+tr[k].w;
}
void rturn(int &k)
{
    int t=tr[k].l;tr[k].l=tr[t].r;tr[t].r=k;
    tr[t].size=tr[k].size;update(k);k=t;
}
void lturn(int &k)
{
    int t=tr[k].r;tr[k].r=tr[t].l;tr[t].l=k;
    tr[t].size=tr[k].size;update(k);k=t;
}
void insert(int &k,int x)
{
    if(k==0)
    {
        size++;k=size;
        tr[k].size=tr[k].w=1;tr[k].v=x;tr[k].rnd=randad();
        return;
    }
    tr[k].size++;
    if(tr[k].v==x)tr[k].w++;
    else if(x>tr[k].v)
    {
        insert(tr[k].r,x);
        if(tr[tr[k].r].rndelse
    {
        insert(tr[k].l,x);
        if(tr[tr[k].l].rndvoid del(int &k,int x)
{
    if(k==0)return; 
    if(tr[k].v==x)
    {
        if(tr[k].w>1)
        {
            tr[k].w--;tr[k].size--;return;
        }
        if(tr[k].l*tr[k].r==0)k=tr[k].l+tr[k].r;
        else if(tr[tr[k].l].rndelse lturn(k),del(k,x);
    }
    else if(x>tr[k].v)
        tr[k].size--,del(tr[k].r,x);
    else tr[k].size--,del(tr[k].l,x);
}
int query_rank(int k,int x)
{
    if(k==0)return 0;
    if(tr[k].v==x)return tr[tr[k].l].size+1;
    else if(x>tr[k].v)
        return tr[tr[k].l].size+tr[k].w+query_rank(tr[k].r,x);
    else return query_rank(tr[k].l,x);
}
int query_num(int k,int x)
{
    if(k==0)return 0;
    if(x<=tr[tr[k].l].size)
        return query_num(tr[k].l,x);
    else if(x>tr[tr[k].l].size+tr[k].w)
        return query_num(tr[k].r,x-tr[tr[k].l].size-tr[k].w);
    else return tr[k].v;
}
void query_pro(int k,int x)
{
    if(k==0)return;
    if(tr[k].velse query_pro(tr[k].l,x);
}
void query_sub(int k,int x)
{
    if(k==0)return;
    if(tr[k].v>x)
    {
        ans=k;query_sub(tr[k].l,x);
    }
    else query_sub(tr[k].r,x);
}
int main()
{
    scanf("%d",&n);
    int opt,x;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&opt,&x);
        switch(opt)
        {
        case 1:insert(root,x);break;
        case 2:del(root,x);break;
        case 3:printf("%d\n",query_rank(root,x));break;
        case 4:printf("%d\n",query_num(root,x));break;
        case 5:ans=0;query_pro(root,x);printf("%d\n",tr[ans].v);break;
        case 6:ans=0;query_sub(root,x);printf("%d\n",tr[ans].v);break;
        }
    }
    return 0;
}

序列treap

BZOJ1500 维护数列

#define INF 2000000000  
#define N 500010  
struct Node;  
Node *null,*root;  
struct Node  
{  
    int w,sz,val,sum,ls,rs,ss,lzy1,lzy2;  
    Node *lft,*rht;  
    void split(int,Node*&,Node*&);  
    void same(int v)  
    {  
        if(this==null) return;  
        lzy2=val=v;  
        sum=v*sz;  
        ls=rs=ss=max(sum,v);  
    }  
    void rev()  
    {  
        if(this==null) return;  
        lzy1^=1;  
        swap(lft,rht);  
        swap(ls,rs);  
    }  
    Node *pushup()  
    {  
        sz=lft->sz+1+rht->sz;  
        sum=lft->sum+val+rht->sum;  

        ls=max(lft->ls,lft->sum+val+max(0,rht->ls));  
        rs=max(rht->rs,rht->sum+val+max(0,lft->rs));  

        ss=max(0,lft->rs)+val+max(0,rht->ls);  
        ss=max(ss,max(lft->ss,rht->ss));  

        return this;  
    }  
    Node *pushdown()  
    {  
        if(lzy1)  
        {  
            lft->rev();  
            rht->rev();  
            lzy1=0;  
        }  
        if(lzy2!=-INF)  
        {  
            lft->same(lzy2);  
            rht->same(lzy2);  
            lzy2=-INF;  
        }  
        return this;  
    }  
};  
Node *merge(Node *p,Node *q)  
{  
    if(p==null) return q;  
    if(q==null) return p;  
    if(p->ww)  
    {  
        p->pushdown();  
        p->rht=merge(p->rht,q);  
        return p->pushup();  
    }  
    q->pushdown();  
    q->lft=merge(p,q->lft);  
    return q->pushup();  
}  
void Node::split(int need,Node *&p,Node *&q)  
{  
    if(this==null)  
    {  
        p=q=null;  
        return;  
    }  
    pushdown();  
    if(lft->sz>=need)  
    {  
        lft->split(need,p,q);  
        lft=null;  
        pushup();  
        q=merge(q,this);  
        return;  
    }  
    rht->split(need-(lft->sz+1),p,q);  
    rht=null;  
    pushup();  
    p=merge(this,p);  
    return;  
}  
Node data[N],*pool[N];  
int top,cnt;  
Node* newnode(int c)  
{  
    Node *x;  
    if(top) x=pool[top--];  
    else x=&data[cnt++];  
    x->lft=x->rht=null;  
    x->sz=1; x->lzy1=0; x->lzy2=-INF;  
    x->val=x->sum=x->ls=x->rs=x->ss=c;  
    x->w=rands();  
    return x;  
}  
void init()  
{  
    cnt=1; top=0;  
    null=&data[0];  
    null->sz=null->sum=0;  
    null->val=null->ls=null->rs=null->ss=-INF;  
    null->lzy1=0;  
    null->lzy2=-INF;  
    null->lft=null->rht=null;  
}  
//---------------------------------------------------------  
void erase(Node *rt)  
{  
    if(rt==null) return;  
    erase(rt->lft);  
    erase(rt->rht);  
    pool[++top]=rt;  
}  
int n,m;  
char ord[20];  
int a,b,c;  
int main ()  
{  
init();  
        root=null;  
        n=fastget();  
        m=fastget();  
        for(int i=0;iwhile (m--)  
        {  
            scanf("%s",ord);  
            Node *p,*q,*r,*s;  
            if(ord[0]=='I')  
            {  
                a=fastget();  
                n=fastget();  
                root->split(a,p,q);  
                for(int i=0;ielse if(ord[0]=='D')  
            {  
                a=fastget();  
                b=fastget();  
                b=a+b-1;  
                root->split(a-1,p,q);  
                q->split(b-a+1,r,s);  
                erase(r);  
                root=merge(p,s);  
            }else if(ord[0]=='M' && ord[2]=='K')  
            {  
                a=fastget();  
                b=fastget();  
                c=fastget();  
                b=b+a-1;  
                root->split(a-1,p,q);  
                q->split(b-a+1,r,s);  
                r->same(c);  
                root=merge(p,merge(r,s));  
            }else if(ord[0]=='R')  
            {  
                a=fastget();  
                b=fastget();  
                b=b+a-1;  
                root->split(a-1,p,q);  
                q->split(b-a+1,r,s);  
                r->rev();  
                root=merge(p,merge(r,s));  
            }else if(ord[0]=='G')  
            {  
                a=fastget();  
                b=fastget();  
                b=a+b-1;  
                root->split(a-1,p,q);  
                q->split(b-a+1,r,s);  
                fastput(r->sum);  
                root=merge(p,merge(r,s));  
            }  
            else if(ord[0]=='M') fastput(root->ss);  
        }  

    return 0;  
}  

重量平衡树&后缀平衡树

BZOJ 3682: Phorni

#include
#include
#include
#include
using namespace std;
template<class T>inline void read(T &res){
    static char ch;T flag=1;
    while((ch=getchar())<'0'||ch>'9')if(ch=='-')flag=-1;res=ch-48;
    while((ch=getchar())>='0'&&ch<='9')res=(res<<1)+(res<<3)+ch-48;res*=flag;
}
#define N 500010
#define LL long long
int n,m,len,type,lastans,x,y;
int ch[N][2],rd[N],cl[N],cnt,root;
LL rk[N];
inline int randlmy(){
    static int seed=173;
    return seed=int(seed*48271LL%2147483647);
}
int cmp(int x,int y){
    return cl[x]1]1]);
}
void rebuild(int &rt,LL l,LL r){
    if(!rt)return;
    rk[rt]=l+r;
    LL mid=(l+r)>>1;
    rebuild(ch[rt][0],l,mid);
    rebuild(ch[rt][1],mid,r);

}
void rotate(int &p,int d,LL l,LL r){
    int q=ch[p][d^1];
    ch[p][d^1]=ch[q][d];
    ch[q][d]=p;
    p=q;
    rebuild(p,l,r);
}
void insert(int &rt,LL l,LL r){
    LL mid=(r+l)>>1;
    if(!rt){rt=cnt;rk[rt]=l+r;return;}
    if(cmp(cnt,rt)){insert(ch[rt][0],l,mid);if(rd[ch[rt][0]]>rd[rt])rotate(rt,1,l,r);}
    else{insert(ch[rt][1],mid,r);if(rd[ch[rt][1]]>rd[rt])rotate(rt,0,l,r);}
}
void insert(int v){
    cl[++cnt]=v;
    rd[cnt]=randlmy()*randlmy();
    insert(root,1,1LL<<61);
}
#define R(rt) rt<<1|1
#define L(rt) rt<<1
int minn[N<<2],p[N];
void build(int rt,int l,int r){
    if(l==r)read(p[l]),minn[rt]=l;
    else{
        int mid=(l+r)>>1,lc=L(rt),rc=R(rt);
        build(lc,l,mid);
        build(rc,mid+1,r);
        minn[rt]=rk[p[minn[lc]]]<=rk[p[minn[rc]]]?minn[lc]:minn[rc];
    }
}
void updata(int rt,int l,int r,int id){
    if(l==r)return;
    int mid=(l+r)>>1,lc=L(rt),rc=R(rt);
    if(id<=mid)updata(lc,l,mid,id);
    else updata(rc,mid+1,r,id);
    minn[rt]=rk[p[minn[lc]]]<=rk[p[minn[rc]]]?minn[lc]:minn[rc];
}
int query(int rt,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr)return minn[rt];
    int mid=(l+r)>>1,lc=L(rt),rc=R(rt);
    if(qr<=mid)return query(lc,l,mid,ql,qr);
    if(ql>mid)return query(rc,mid+1,r,ql,qr);
    int vl=query(lc,l,mid,ql,qr),vr=query(rc,mid+1,r,ql,qr);
    return rk[p[vl]]<=rk[p[vr]]?vl:vr;
}
char s[N],cmd[5];
int main(){
    read(n),read(m),read(len),read(type);
    scanf("%s",s);
    for(register int i=1;i<=len;i++)
        insert(s[len-i]-'a');
    build(1,1,n);
    while(m--){
        scanf("%s",cmd);
        if(!type)lastans=0;
        if(cmd[0]=='I')
            read(x),insert(x^lastans),++len;
        else if(cmd[0]=='C')
            read(x),read(p[x]),updata(1,1,n,x);
        else
            read(x),read(y),
            printf("%d\n",lastans=query(1,1,n,x,y));
    }
    return 0;
}

可持久化Treap

POJ 3580 SuperMemo

#include  
#include  
#include  
#include  
#include  
#include  
using namespace std;  
struct treap_node{  
    treap_node *left,*right;  
    int val,fix,size,wgt,minn,adel,rdel;  
    treap_node(int val): val(val) {left=right=NULL; fix=rand(); wgt=size=1; minn=val; rdel=adel=0; }  
    int lsize()  
      {  
        if (left)  
          return left->size;  
        else   
          return 0;  
      }  
    int rsize()  
      {  
        if (right)  
          return right->size;  
        else  
          return 0;  
      }  
    void updata()  
      {  
        minn=val;  
        if (left)  
          minn=min(minn,left->minn+left->adel);  
        if (right)  
          minn=min(minn,right->minn+right->adel);  
      }  
    void pushdown()  
      {  
        treap_node *temp;  
        if (adel)  
          {  
            minn+=adel;  
            val+=adel;  
            if (left)  
              left->adel+=adel;  
            if (right)  
              right->adel+=adel;  
            adel=0;  
          }  
        if (rdel%2)  
          {  
            if (left==NULL||right==NULL)  
              {  
                if (left==NULL)  
                  {  
                    left=right;  
                    right=NULL;  
                  }  
                else  
                  {  
                    right=left;  
                    left=NULL;  
                  }  
              }  
            else  
              {  
                temp=left;  
                left=right;  
                right=temp;  
              }  
            if (left)  
            left->rdel+=rdel;  
            if (right)  
            right->rdel+=rdel;  
            rdel=0;  
          }  
        updata();  
      }  
    void Maintain()  
      {  
        size=wgt;  
        size+=lsize()+rsize();  
      }  
};  
int n,m;  
treap_node *root;  
typedef pair droot;  
treap_node *merge(treap_node *a,treap_node *b)  
{  
    if (!a) return b;  
    if (!b) return a;  
    a->pushdown(); b->pushdown();  
    a->updata(); b->updata();  
    if (a->fixfix)  
      {  
        a->right=merge(a->right,b);  
        a->updata();  
        a->Maintain();  
        return a;  
      }  
    else  
      {  
        b->left=merge(a,b->left);  
        b->updata();  
        b->Maintain();  
        return b;  
      }   
}  
droot split(treap_node *a,int k)  
{   
    if (!a) return droot(NULL,NULL);  
    droot y;  
    a->pushdown();   a->updata();  
    if (a->lsize()>=k)  
      {  
        y=split(a->left,k);  
        a->left=y.second;  
        a->updata();  
        a->Maintain();  
        y.second=a;  
      }  
    else  
      {  
        y=split(a->right,k-a->lsize()-1);  
        a->right=y.first;  
        a->updata();  
        a->Maintain();  
        y.first=a;  
      }  
    return y;  
}  
void insert(int k,int value)  
{  
    treap_node *temp;  
    droot y=split(root,k);  
    temp=new treap_node(value);  
    root=merge(merge(y.first,temp),y.second);  
}  
void del(int k)  
{  
    droot x,y;  
    x=split(root,k-1);  
    y=split(x.second,1);  
    root=merge(x.first,y.second);  
}  
int main()  
{  
    char s[20];  
    droot ai,bi,ci;  
    treap_node *temp;  
    int i,x,y,a,L,t;  
    scanf("%d",&n);  
    for (i=1;i<=n;++i)  
      {  
        scanf("%d",&x);  
        insert(i,x);  
      }  
    scanf("%d",&m);  
    for (i=1;i<=m;++i)  
      {  
        scanf("%s",&s);  
        if (s[0]=='A')  
          {  
            scanf("%d%d%d",&x,&y,&a);  
            ai=split(root,x-1);  
            bi=split(ai.second,y-x+1);  
            bi.first->adel+=a;  
            ai.second=merge(bi.first,bi.second);  
            root=merge(ai.first,ai.second);  
          }  
        if (s[0]=='I')  
          {  
            scanf("%d%d",&x,&a);  
            insert(x,a);  
          }  
        if (s[0]=='D')  
          {  
            scanf("%d",&x);  
            del(x);  
          }  
        if (s[0]=='R')  
          {  
            if (s[3]=='E')  
              {  
                scanf("%d%d",&x,&y);  
                ai=split(root,x-1);  
                bi=split(ai.second,y-x+1);    
                bi.first->rdel++;  
                ai.second=merge(bi.first,bi.second);  
                root=merge(ai.first,ai.second);  
              }  
            if (s[3]=='O')  
              {  
                scanf("%d%d%d",&x,&y,&a);  
                L=y-x+1;  
                a=(a%L+L)%L;  
                ai=split(root,x-1);   
                bi=split(ai.second,L);  
                ci=split(bi.first,L-a);  
                bi.first=merge(ci.second,ci.first);  
                ai.second=merge(bi.first,bi.second);  
                root=merge(ai.first,ai.second);  
              }    
          }  
        if (s[0]=='M')  
          {  
            scanf("%d%d",&x,&y);  
            ai=split(root,x-1);  
            bi=split(ai.second,y-x+1);   
            t=bi.first->minn;  
            ai.second=merge(bi.first,bi.second);  
            root=merge(ai.first,ai.second);  
            printf("%d\n",t);    
          }  
      }  
}  

补一句,多年的超文本编辑器问题也解决了。。。。
TREAP最强,TREAP赛高!!

你可能感兴趣的:(可持久化,数据结构与算法)