1. 程式人生 > >最強平衡樹——Treap[以我的最弱擊敗你的最強]

最強平衡樹——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<iostream>
#include<cstdio>
#include<cstdlib>
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].rnd<tr[k].rnd)lturn(k);
    }
    else
    {
        insert(tr[k].l,x);
        if(tr[tr[k].l].rnd<tr[k].rnd)rturn(k);
    } 
}
void 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].rnd<tr[tr[k].r].rnd)
            rturn(k),del(k,x);
        else 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].v<x)
    {
        ans=k;query_pro(tr[k].r,x);
    }
    else 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->w<q->w)  
    {  
        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;i<n;i++)  
        {  
            a=fastget();  
            root=merge(root,newnode(a));  
        }  
        while (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;i<n;i++)  
                {  
                    b=fastget();  
                    p=merge(p,newnode(b));  
                }  
                root=merge(p,q);  
            }else 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<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
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]<cl[y]||(cl[x]==cl[y]&&rk[x-1]<rk[y-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<iostream>  
#include<cstdio>  
#include<cstring>  
#include<ctime>  
#include<cstdlib>  
#include<algorithm>  
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<treap_node*,treap_node*> 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->fix<b->fix)  
      {  
        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賽高!!

相關推薦

平衡——Treap[擊敗]

僕の最弱を以て,君の最強を打ち破る。!!——Treap 本人蒟蒻,在平衡樹坑中深陷數年。為了早日逃離此天坑,特作此文。 什麼是平衡樹?度娘傳送門 什麼是treap?ACdreamers%%% 注:本篇所有程式碼都在片尾!!(醒目) CMP 那麼瞭解了

【bzoj3224】普通平衡——treap

blog lib mes cas style tree upd treap ins 我的第一道treap題目,treap的模版題。 代碼是對著hzw的敲的,一邊敲一邊理解。。。 主要是熟悉一下treap的各種基本操作,詳細細節看代碼。 #include<cstdio

bzoj3224Tyvj 1728 普通平衡 treap

amp turn clas algo 。。 pac rip problem upd 3224: Tyvj 1728 普通平衡樹Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 17706 Solved: 7764[Submit

平衡Treap模板與原理

優化 排名 print 比較 pla ans for 後繼 每一個 這次我們來講一講Treap(splay以後再更) 平衡樹是一種排序二叉樹(或二叉搜索樹),所以排序二叉樹可以迅速地判斷兩個值的大小,當然操作肯定不止那麽多(不然我們還學什麽)。 而平衡樹在排序二叉樹的基礎上

luoguP3369[模板]普通平衡(Treap/SBT) 題解

names main getchar() clu 父親節 ble blank fine while 鏈接一下題目:luoguP3369[模板]普通平衡樹(Treap/SBT) #include<iostream> #include<cstdlib>

[洛谷P3369] 普通平衡 Treap & Splay

mes href using oid org 題目 scanf printf std 這個就是存一下板子...... 題目傳送門 Treap的實現應該是比較正經的。 插入刪除前驅後繼排名什麽的都是平衡樹的基本操作。 1 #include<cstdio>

7.Bzoj3224: Tyvj 1728 普通平衡(Treap)

Bzoj3224: Tyvj 1728 普通平衡樹(Treap) 終於自己敲出來了Treap。。。。。。拿來當板子還是挺好用的. 操作1,顯然根據二叉搜尋樹的性質直接建就好了. 操作2,如果有兩個兒子,則把這個點下旋下去,直到只有一個兒子或者沒有. 操作3,查詢比他小的數,記錄一個size,表示這個點有多少

【模板】平衡——Treap和Splay

二叉搜尋樹($BST$):一棵帶權二叉樹,滿足左子樹的權值均小於根節點的權值,右子樹的權值均大於根節點的權值。且左右子樹也分別是二叉搜尋樹。(如下) $BST$的作用:維護一個有序數列,支援插入$x$,刪除$x$,查詢排名為$x$的數,查詢$x$的排名,求$x$的前驅後繼等操作。 時間複雜度:$O(運

資料結構之平衡(Treap)

平衡樹是二叉搜尋樹和堆合併構成的新資料結構,所以它的名字取了Tree和Heap各一半,叫做Treap。 堆和樹的性質是衝突的,二叉搜尋樹滿足左子樹<根節點<右子樹,而堆是滿足根節點小於等於(或大於等於)左右兒子。因此在Treap的資料結構中,並不是

POJ 1442 平衡Treap新模板

題意:輸入m個數,詢問n個數,第一個數如果是3,就輸出在m的第三個數輸入完成後第1大的數,第二個就輸出第二大的數,但前提都是在輸入完U[i]個數後 思路:用平衡樹Treap進行插入和查詢第K大的數,模版題 #include <stdio.h> #include

BZOJ 1208 平衡Treap模版題

題意:不描述了 思路:我們只需要一個樹就可以,輸入一個數就存進去,當人和動物都大於0的時候,開始給人分配寵物,人的期望值b的排名k,找到k-1的數和k+1的數,比較哪個離b更近,人多還是動物動情況一樣不用分開討論,然後加起來取餘輸出,簡單題#include <std

洛谷P3369 普通平衡(Treap/Splay)

題目描述 您需要寫一種資料結構(可參考題目標題),來維護一些數,其中需要提供以下操作: 1. 插入x數 2. 刪除x數(若有多個相同的數,因只刪除一個) 3. 查詢x數的排名(若有多個相同的數,因輸出最小的排名) 4. 查詢排名為x的數 5.

【模板】普通平衡 Treap

題目描述 您需要寫一種資料結構(可參考題目標題),來維護一些數,其中需要提供以下操作: 1.插入x數 2.刪除x數(若有多個相同的數,因只刪除一個) 3.查詢x數的排名(排名定義為比當前數小的數的個數+1。若有多個相同的數,因輸出最小的排名) 4.查詢

重量平衡Treap隨機優先級來維護堆結構,並滿足BST性質

神奇 upd 調整 cst clas 就是 int 元素 每一個 關於重量平衡樹的相關概念可以參考姊妹文章:重量平衡樹之替罪羊樹 Treap是依靠旋轉來維護平衡的重量平衡樹中最為好寫的一中,因為它的旋轉不是LL就是RR 對於每一個新的節點,它給這個節點分配了一個隨機數,用作

leetcode Minimum Depth of Binary Tree (平衡小深度)

leetcode 題目:https://leetcode.com/problems/minimum-depth-of-binary-tree/ Minimum Depth of Binary Tree ping 平衡樹的最小深度 解題思路:    1.遞迴求

史上詳盡的平衡(splay)講解與模板

首先宣告:萬分感謝gty大哥的幫助!這年頭能找到簡單易懂的陣列版平衡樹模板只能靠學長了! 變數宣告:f[i]表示i的父結點,ch[i][0]表示i的左兒子,ch[i][1]表示i的右兒子,key[i]表示i的關鍵字(即結點i代表的那個數字),cnt[i]表示i結點的關鍵

2017-2018 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2017) 部分題/平衡小環/思路bfs

交題地址 難度按照順序遞增 J - Judging Moose 隊友敲的 #include <iostream> #include <cstdio> using namespace std; int main() {

所見過的簡短、靈活的javascript日期轉字符串工具函數

var gets java cti return -m func date 靈活 我們知道javascript的Date對象並沒有提供日期格式化函數。將日期對象轉換成"2015-7-02 20:35:11"等這樣的格式又是項目中非經常常使用的需求。近期在我們項目中看到了

Behavior Tree 用 Lua 實現一個簡行為

urn ret pri end put true for 行為樹 一個 1 local SELECTOR = 1 2 local SEQUENCE = 2 3 local CONDITION = 3 4 local ACTION = 4 5 6 loca

【BZOJ4519】[Cqoi2016]不同的小割 小割

main href family iostream 有趣的 rip tput ans val 【BZOJ4519】[Cqoi2016]不同的最小割 Description 學過圖論的同學都知道最小割的概念:對於一個圖,某個對圖中結點的劃分將圖中所有結點分成兩個部分,