zoukankan      html  css  js  c++  java
  • 【bzoj3224】Tyvj 1728 普通平衡树 01Trie姿势+平衡树的四种姿势 :splay,旋转Treap,非旋转Treap,替罪羊树

    直接上代码 正所谓 人傻自带大常数

    平衡树的几种姿势:  AVL Red&Black_Tree 码量爆炸,不常用;SBT 出于各种原因,不常用。

                                     常用:

                                      Treap 旋转 基于旋转操作和随机数堆 但不支持区间操作。

                                                非旋转 基于随机数堆和拆分合并操作 常数较大 

                                                时间复杂度:很难被卡,均摊O(logN)

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #define MAXN 100005
    using namespace std;
    int ch[MAXN][2],key[MAXN],r[MAXN],size[MAXN],cnt[MAXN],root,sz,n,m;
    inline void update(int x)
    {
       size[x]=size[ch[x][1]]+size[ch[x][0]]+cnt[x];
    }
    inline void rotate(int &x)
    {
        int wh=r[ch[x][1]]>r[ch[x][0]],son=ch[x][wh];
        ch[x][wh]=ch[son][wh^1];
        ch[son][wh^1]=x;
        update(x);
        update(son);
        x=son;
    }
    void insert(int &now,int x)
    {
        if(!now)
        {
           now=++sz;
           cnt[sz]=size[sz]=1;
           key[sz]=x;
           r[sz]=(rand()%100+rand());
           return;
        }
        if(key[now]==x)
        {
           cnt[now]++;
           size[now]++;
           return;
        }
        insert(ch[now][key[now]<x],x);
        if(r[now]<r[ch[now][key[now]<x]])
          rotate(now);
        else
          update(now);
    }
    void del(int &now,int x)
    {
        if(key[now]==x)
        {
           if(cnt[now]>1)
           {
             cnt[now]--;
             size[now]--;
             return;
           }
           if(ch[now][1]*ch[now][0]==0)
           {
             now=ch[now][1]+ch[now][0];
             return;
           }
           rotate(now);
           del(ch[now][key[ch[now][1]]==x],x);
           update(now);
           return;
        }
        del(ch[now][key[now]<x],x);
        update(now);
    }
    inline int kth(int x)
    {
       int now=root;
       while(1)
       {
          if(size[ch[now][0]]>=x)
          {
            now=ch[now][0];
            continue;
          }
          int lon=cnt[now]+size[ch[now][0]];
          if(lon>=x)
           return key[now];
          x-=lon;
          now=ch[now][1];
       }
    }
    inline int rank(int x)
    {
       int now=root,ans=0;
       while(1)
       {
          if(key[now]==x)
            return ans+1+size[ch[now][0]];
          if(x<key[now])
          {
             now=ch[now][0];
             continue;
          }
          ans+=cnt[now]+size[ch[now][0]];
          now=ch[now][1];
       }
    }
    inline int pre(int x)
    {
       int now=root,ans=-0x7fffffff;
       while(now)
       if(key[now]<x)
       {
          if(key[now]>ans)
           ans=key[now];
          now=ch[now][1];
       }
       else
         now=ch[now][0];
       return ans;
    }
    inline int next(int x)
    {
       int now=root,ans=0x7fffffff;
       while(now)
       if(key[now]>x)
       {
          if(key[now]<ans)
           ans=key[now];
          now=ch[now][0];
       }
       else
         now=ch[now][1];
       return ans;
    }
    int main()
    {
        freopen("phs.in","r",stdin);
        freopen("phs.out","w",stdout);
        scanf("%d",&n);
        while(n--)
        {
           int x,y;
           scanf("%d%d",&y,&x);
           switch(y)
           {
             case 1:insert(root,x);break;
             case 2:del(root,x);break;
             case 3:printf("%d
    ",rank(x));break;
             case 4:printf("%d
    ",kth(x));break;
             case 5:printf("%d
    ",pre(x));break;
             case 6:printf("%d
    ",next(x));break;
           }
        }
        return 0;
    }
    旋转Treap
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<ctime>
    #include<cstdlib>
    #define MAXN 100010
    using namespace std;
    inline int read()
    {
       int sum=0,f=1;
       char ch=getchar();
       while(ch<'0'||ch>'9')
       {
           if(ch=='-')f=-1;
           ch=getchar();
       }
       while(ch>='0'&&ch<='9')
       {
          sum=(sum<<1)+(sum<<3)+ch-'0';
          ch=getchar();
       }
       return sum*f;
    }
    struct Treap
    {
         struct Node
         {
            Node *ch[2];
            int key,v,size;
            void pushup()
            {
               size=ch[1]->size+ch[0]->size+1;
            }
         }null[MAXN],*root,*stack[MAXN];
         int top;
         void Init()
         {
            top=0;
            root=null;
            null->ch[1]=null->ch[0]=null;
            for(int i=1;i<MAXN;i++)stack[++top]=null+i;
         }
         Node *New(int key)
         {
            Node *p=stack[top--];
            p->ch[1]=p->ch[0]=null;
            p->size=1;
            p->key=key;
            p->v=rand();
            return p;
         }
         Node *Merge(Node *a,Node *b)
         {
           if(a==null)return b;
           if(b==null)return a;
           if(a->v<b->v)
           {
              a->ch[1]=Merge(a->ch[1],b);
              a->pushup();
              return a;
           }
           else
           {
              b->ch[0]=Merge(a,b->ch[0]);
              b->pushup();
              return b;
           }
         }
         pair<Node*,Node*> split(Node *x,int k)
         {
             if(x==null)return make_pair(null,null);
             if(x->ch[0]->size>=k)
             {
                pair<Node*,Node*> y=split(x->ch[0],k);
                x->ch[0]=y.second;
                x->pushup();
                y.second=x;
                return y;
             }
             else
             {
                pair<Node*,Node*> y=split(x->ch[1],k-x->ch[0]->size-1);
                x->ch[1]=y.first;
                x->pushup();
                y.first=x;
                return y;
             }
         }
         int getrank(Node *p,int key)
         {
              if(p==null)return 0;
              return p->key>=key?getrank(p->ch[0],key):getrank(p->ch[1],key)+p->ch[0]->size+1;
         }
         int getkth(int k)
         {
              Node *now=root;
              while(1)
               if(now->ch[0]->size>=k)
                now=now->ch[0];
               else 
                if(now->ch[0]->size+1==k)
                 return now->key;
                else 
                 k-=now->ch[0]->size+1,now=now->ch[1];
         }
         void insert(int key)
         {
              int k=getrank(root,key);
              pair<Node*,Node*> x=split(root,k);
              Node *p=New(key);
              root=Merge(Merge(x.first,p),x.second);
         }
         void del(int key)
         {
              int k=getrank(root,key);
              pair<Node*,Node*> x=split(root,k);
              pair<Node*,Node*> y=split(x.second,1);
              stack[++top]=y.first;
              root=Merge(x.first,y.second);
         }
         int prefix(int key)
         {
              return getkth(getrank(root,key));
         }
         int suffix(int key)
         {
              return getkth(getrank(root,key+1)+1);
         }
    }YY;
    int main()
    {
      freopen("phs.in","r",stdin);
        freopen("phs.out","w",stdout);
      YY.Init();
      int T=read();
      while(T--)
      {
          int opt=read();
          int x=read();
          switch(opt)
          {
             case 1:YY.insert(x);
                    break;
             case 2:YY.del(x);
                    break;
             case 3:printf("%d
    ",YY.getrank(YY.root,x)+1);
                    break;
             case 4:printf("%d
    ",YY.getkth(x));
                    break;
             case 5:printf("%d
    ",YY.prefix(x));
                    break;
             case 6:printf("%d
    ",YY.suffix(x));
                    break;
          }
      }
      return 0;
    }
    非旋转Treap

                                      PS:非旋转可以实现平衡树的可持久化,还能来套一些东西

                                      Spaly 完全基于旋转 各种操作 

                                                时间复杂度:引用:“ 称单旋无神犇,双旋O(logN),这句话我也没有考证,个人表示不想做什么太多的探究”。毕竟Splay的复杂度本来就挺玄学的了,而且专门卡单旋Splay的题也没怎么听说过。

    #include<cstdio>
    #define MAXN 200005
    using namespace std;
    int key[MAXN],ch[MAXN][2],cnt[MAXN],size[MAXN],f[MAXN],n,sz,root;
    inline void clear(int x)
    {
        key[x]=ch[x][0]=ch[x][1]=cnt[x]=size[x]=f[x]=0;
    }
    inline int get(int x)
    {
        return ch[f[x]][1]==x;
    }
    inline void update(int x)
    {
        size[x]=cnt[x]+size[ch[x][1]]+size[ch[x][0]];
    }
    inline void rotate(int x)
    {
        int fa=f[x],pa=f[fa],what=get(x);
        if(pa){ch[pa][fa==ch[pa][1]]=x;}
        ch[fa][what]=ch[x][what^1];
        f[ch[fa][what]]=fa;
        ch[x][what^1]=fa;
        f[fa]=x;
        f[x]=pa;
        update(fa);
        update(x);
    }
    inline void splay(int x)
    {
        for(int fa;(fa=f[x]);rotate(x))
         if(f[fa])
          rotate((get(x)==get(fa)?fa:x));
        root=x;
    }
    inline void insert(int x)
    {
        if(!root)
        {
           sz++;
           ch[sz][1]=ch[sz][0]=f[sz]=0;
           key[sz]=x;
           cnt[sz]=size[sz]=1;
           root=sz;
           return;
        }
        int now=root,fa=0;
        while(1)
        {
           if(key[now]==x)
           {
              cnt[now]++;
              splay(now);
              return;
           }
           fa=now;
           now=ch[now][key[now]<x];
           if(!now)
           {
              sz++;
              f[sz]=fa;
              ch[sz][1]=ch[sz][0]=0;
              key[sz]=x;
              cnt[sz]=1;
              ch[fa][key[fa]<x]=sz;
              splay(sz);
              return;
           }
        }
    }
    inline void find(int x)
    {
        int now=root;
        while(1)
        {
           if(x<key[now])
           {
             now=ch[now][0];
             continue;
           }
           if(key[now]==x)
           {
             splay(now);
             return;
           }
           now=ch[now][1];
        }
    }
    inline int rank(int x)
    {
        find(x);
        return size[ch[root][0]]+1;
    }
    inline int findx(int x)
    {
        int now=root;
        while(1)
        {
           if(size[ch[now][0]]>=x)
           {
              now=ch[now][0];
              continue;
           }
           int lon=size[ch[now][0]]+cnt[now];
           if(x<=lon)
            return key[now];
           x-=lon;
           now=ch[now][1];
        }
    }
    inline void del(int x)
    {
        find(x);
        if(cnt[root]>1){cnt[root]--;return;}
        if(size[root]==1){clear(root);root=0;return;}
        if (!ch[root][0]){ int oldroot=root;root=ch[root][1];f[root]=0;clear(oldroot);return;  
         }  
         else if (!ch[root][1]){  
              int oldroot=root;root=ch[root][0];f[root]=0;clear(oldroot);return;  
         }  
        int now=ch[root][0],old=root;
        while(ch[now][1])now=ch[now][1];
        f[ch[old][1]]=now;
        ch[now][1]=ch[old][1];
        f[ch[old][0]]=0;
        clear(old);
        splay(now);
        return;
    }
    inline int pre(int x)
    {
        insert(x);
        int now=ch[root][0];
        while(ch[now][1])now=ch[now][1];
        del(x);
        return key[now];
    }
    inline int next(int x)
    {
        insert(x);
        int now=ch[root][1];
        while(ch[now][0])now=ch[now][0];
        del(x);
        return key[now];
    }
    int main()
    {
        scanf("%d",&n);
        while(n--)
        {
           int x,y;
           scanf("%d%d",&y,&x);
           switch(y)
           {
             case 1:insert(x);break;
             case 2:del(x);break;
             case 3:printf("%d
    ",rank(x));break;
             case 4:printf("%d
    ",findx(x));break;
             case 5:printf("%d
    ",pre(x));break;
             case 6:printf("%d
    ",next(x));break;
           }
        }
        return 0;
    }
    Splay

                                      ScapeGoat_Tree 基于a权值平衡树和压扁重构 无旋转 但不支持区间操作;运用a权值平衡树一定是a高度平衡树来维持log的效率;主要操作就是拍扁重建,但是为了解决删除时的繁冗讨论所以维持一个带有已删除点的残树,维持这棵树的高度,同时在维护时维护这棵树的残点不超过一定比例;如果不用cnt那么删除时一定要用找排名的方式,这样的话会防止原来的一子链重建后成为人字链

                                              时间复杂度:最坏会被卡到O(n2)(实际上∑(㏒₂n/i)*(㏒₂i)*i)(只是重建)但是那是把区间从大到小输入(或相反),实际上这是不加常数的结果(此处常数指替罪羊判断不平衡时除了alpha以外的那个常数),一般会是均摊logn(CTR会为了性命而不敢去卡)

    #include<cstdio>
    #include<iostream>
    using namespace std;
    const int MAXN=200010;
    const double a=0.75;
    struct node
    {
        node *ch[2];
        int key,size,cover,ex;
        inline void update()
        {
           size=ch[0]->size+ch[1]->size+ex;
           cover=ch[0]->cover+ch[1]->cover+1;
        }
        inline bool bad()
        {
            return ch[0]->cover>=cover*a+5||ch[1]->cover>=cover*a+5;
        }
    }Mem[MAXN],*null,*root,*stack[MAXN],*lst[MAXN];
    int len,top;
    inline void Init()
    {
        root=null=Mem;
        null->size=null->cover=null->ex=0;
        null->ch[0]=null->ch[1]=Mem;
        for(int i=1;i<MAXN;i++)stack[++top]=Mem+i;
    }
    inline node *New(int key)
    {
        node *t=stack[top--];
        t->ch[0]=t->ch[1]=null;
        t->size=t->cover=t->ex=1;
        t->key=key;
        return t;
    }
    inline void travel(node *p)
    {
        if(p==null)return;
        travel(p->ch[0]);
        if(p->ex)lst[++len]=p;
        else stack[++top]=p;
        travel(p->ch[1]);
    }
    inline node *divide(int l,int r)
    {
        if(l>r)return null;
        int mid=(l+r)>>1;
        lst[mid]->ch[0]=divide(l,mid-1);
        lst[mid]->ch[1]=divide(mid+1,r);
        lst[mid]->update();
        return lst[mid];
    }
    inline void rebuild(node *&p)
    {
        len=0;
        travel(p);
        p=divide(1,len);
    }
    inline node **insert(node *&p,int key)
    {
        if(p==null)
        {
            p=New(key);
            return &null;
        }
        p->size++;
        p->cover++;
        node **ret=insert(p->ch[p->key<=key],key);
        if(p->bad())ret=&p;
        return ret;
    }
    inline void erace(node *p,int k)
    {
        //cout<<p->ch[0]->size<<endl;
        p->size--;
        if(p->ex&&k==p->ch[0]->size+1)
        {
            p->ex=0;
            return;
        }
        if(k<=p->ch[0]->size)erace(p->ch[0],k);
        else erace(p->ch[1],k-p->ch[0]->size-p->ex);
    }
    inline int Kth(int k)
    {
        node *p=root;
        while(p!=null)
        {
             if(p->ex&&k==p->ch[0]->size+1)return p->key;
             else if(p->ch[0]->size>=k)p=p->ch[0];
             else k-=p->ch[0]->size+p->ex,p=p->ch[1];
        }
    }
    inline int Rank(int x)
    {
        node *p=root;
        int ret=1;
        while(p!=null)
         if(p->key>=x)
          p=p->ch[0];
         else 
          ret+=p->ch[0]->size+p->ex,p=p->ch[1];
        return ret;
    }
    inline void Insert(int x)
    {
        node **p=insert(root,x);
        if(*p!=null)rebuild(*p);
    }
    inline void Erace_kth(int k)
    {
        erace(root,k);
        if(root->size<root->cover*a)rebuild(root);
    }
    inline void Erace(int x)
    {
        Erace_kth(Rank(x));
    }
    int main()
    {
        freopen("phs.in","r",stdin);
        freopen("phs.out","w",stdout);
        Init();
        int Q,opt,x;
        scanf("%d",&Q);
        while(Q--)
        {
            scanf("%d%d",&opt,&x);
            switch(opt)
            {
                case 1:Insert(x);break;
                case 2:Erace(x);break;
                case 3:printf("%d
    ",Rank(x));break;
                case 4:printf("%d
    ",Kth(x));break;
                case 5:printf("%d
    ",Kth(Rank(x)-1));break;
                case 6:printf("%d
    ",Kth(Rank(x+1)));break;
            }
        }
    }
    ScapeGoat——Tree

     打了四种平衡树,发现01Trie最快还™短..........

    #include <cstdio>
    using namespace std;
    const int A=24,fix=10000000;
    inline void read (int &now){
        register char word=getchar();bool temp=false;
        for(now=0;word<'0'||word>'9';word=getchar())if(word=='-')temp=true;
        for(;word>='0'&&word<='9';now=(now<<1)+(now<<3)+word-'0',word=getchar());
        if(temp)now=-now;
    }
    struct Trie{
      Trie *ch[2];int size;
      void* operator new(size_t);
    }*root,*null,*C,*mempool;
    void* Trie :: operator new(size_t){
      if(C==mempool)C=new Trie[(1<<21)+10],mempool=C+(1<<21)+10;
      return C++;
    }
    inline Trie *New(){
      register Trie *p=new Trie;
      p->ch[0]=p->ch[1]=null,p->size=0;
      return p;
    }
    int n;
    inline void Insert(int x,int size){
      register Trie *p=root;x+=fix;
      for(int i=A;i>=0;i--){
        if(p->ch[(x>>i)&1]==null)p->ch[(x>>i)&1]=New();
        p=p->ch[(x>>i)&1];p->size+=size;
      }
    }
    inline int get_Rank(int x){
      register int ret=0;x+=fix;register Trie *p=root;
      for(register int i=A;i>=0&&p!=null;i--)
        if(x&(1<<i))ret+=p->ch[0]->size,p=p->ch[1];
        else p=p->ch[0];
      return ret;
    }
    inline int get_Kth(int k){
      register Trie *p=root;register int ret=0;
      for(register int i=A;i>=0;i--)
        if(p->ch[0]->size>=k)p=p->ch[0];
        else ret|=(1<<i),k-=p->ch[0]->size,p=p->ch[1];
      return ret-fix;
    }
    int main(){
      freopen("phs.in","r",stdin);freopen("phs.out","w",stdout);
      null=new Trie,null->ch[0]=null->ch[1]=null,null->size=0,root=new Trie,root->ch[0]=root->ch[1]=null,root->size=0;
      read(n);register int opt,x;
      while(n--){
        read(opt),read(x);
        switch(opt){
          case 1:Insert(x,1);break;
          case 2:Insert(x,-1);break;
          case 3:printf("%d
    ",get_Rank(x)+1);break;
          case 4:printf("%d
    ",get_Kth(x));break;
          case 5:printf("%d
    ",get_Kth(get_Rank(x)));break;
          case 6:printf("%d
    ",get_Kth(get_Rank(x+1)+1));break;
        }
      }
    }
    01Trie
  • 相关阅读:
    https://pingcap.com/blog-cn/flame-graph/
    https://software.intel.com/sites/landingpage/pintool/docs/97998/Pin/html/
    http://boostorg.github.io/stacktrace/stacktrace/getting_started.html#stacktrace.getting_started.how_to_print_current_call_stack
    线程局部存储
    slice 切片实现 Slice object interface
    网络分裂 redis 集群
    vscode-sftp
    Sizes of integer types 整形字节长度 系统字节
    学件中心
    源码 版本
  • 原文地址:https://www.cnblogs.com/TSHugh/p/6986618.html
Copyright © 2011-2022 走看看