【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\n",rank(x));break;
         case 4:printf("%d\n",kth(x));break;
         case 5:printf("%d\n",pre(x));break;
         case 6:printf("%d\n",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\n",YY.getrank(YY.root,x)+1);
                break;
         case 4:printf("%d\n",YY.getkth(x));
                break;
         case 5:printf("%d\n",YY.prefix(x));
                break;
         case 6:printf("%d\n",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\n",rank(x));break;
         case 4:printf("%d\n",findx(x));break;
         case 5:printf("%d\n",pre(x));break;
         case 6:printf("%d\n",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\n",Rank(x));break;
            case 4:printf("%d\n",Kth(x));break;
            case 5:printf("%d\n",Kth(Rank(x)-1));break;
            case 6:printf("%d\n",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\n",get_Rank(x)+1);break;
      case 4:printf("%d\n",get_Kth(x));break;
      case 5:printf("%d\n",get_Kth(get_Rank(x)));break;
      case 6:printf("%d\n",get_Kth(get_Rank(x+1)+1));break;
    }
  }
}
01Trie

 

转载于:https://www.cnblogs.com/TSHugh/p/6986618.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值