0x46のブルーブックの練習:一般的なバランスの取れたツリー

Treap /バランスバイナリツリー


ブルーブック問題:一般的なバランスツリー

この質問は、バランスの取れたツリーテンプレートの問題で、あなたが最も簡単なTreap、様々な操作の考え方について、以下に簡単に複数のソリューションを、使用することができます

  • 追加
    新(ヴァル):あなたは、pはサブツリーのルートノードが空であるか否かが判断される加算する値を追加したい場合は、新しいノードが空で追加。新しいノードを追加するとき、もちろんバランスの取れた木の、DATノード子供が理解しやすい[P]の.dat、回転させるには、コードの利き手を参照してくださいよりも大きくなります。

    void Insert(int &p,int val){
      if(!p){
          p=New(val);
          return;
      }
      if(val==a[p].val){
          a[p].cnt++,Updata(p);
          return;
      }
      if(val<a[p].val){
          Insert(a[p].l,val);
          if(a[p].dat<a[a[p].l].dat) zig(p);
      }
      else{
          Insert(a[p].r,val);
          if(a[p].dat<a[a[p].r].dat) zag(p);
      }
      Updata(p);
    }
  • 削除:
    バランスの取れたツリーの削除が容易、それはノードが葉にスピン削除した後、削除されます。参照コード

    void Remove(int &p,int val){
      if(p==0) return;
      if(val==a[p].val){
          if(a[p].cnt>1){     //val这个值有重复,直接减少cnt即可
              a[p].cnt--,Updata(p);
              return;
          }
          if(a[p].l||a[p].r){     //p有子树,不是叶子
              if(a[p].r==0||a[a[p].l].dat > a[a[p].r].dat) zig(p),Remove(a[p].r,val);     //左子树长于右子树,向右旋
              else zag(p),Remove(a[p].l,val);
              Updata(p);
          }
          else p=0;               //p是叶子直接删除
          return;
      }
      if(val<a[p].val) Remove(a[p].l,val);
      else Remove(a[p].r,val);
      Updata(p);
    
    }
  • 出力順位の値:
    平衡二分木、左端の最小値の性質は、私は、左サブツリーSIZ Pの場合、P順位が[P] .L]であることを知って 、+ 1 .siz これによりますポイント。ヴァル<[P] .val場合、valが再帰的に左サブツリーを処理する、左サブツリーに記載しました。ときに左サブツリーSIZ戻り値と繰り返し周波数P及びPこれは再帰右サブツリー戻り値は右ヴァル再帰右サブツリーに示されているが原因であるCNTヴァル> [P] .val、サブツリーは、左の部分木とp valをよりvalを大きな、ランキングが、簡単に知ることが。

    int GetRankByVal(int p,int val){
      if(p==0) return 0;
      if(val==a[p].val) return a[a[p].l].siz+1;
      else if(val<a[p].val) return GetRankByVal(a[p].l,val);
      return GetRankByVal(a[p].r,val)+a[a[p].l].siz+a[p].cnt;
    }
    
  • ランキングの出力値:
    コードでこの外観。

    int GetvalByRank(int p,int rak){
      if(p==0) return INF;
      if(a[a[p].l].siz>=rak) return GetvalByRank(a[p].l,rak); 
      if(a[a[p].l].siz+a[p].cnt>=rak) return a[p].val;        
      return GetvalByRank(a[p].r,rak-a[a[p].l].siz-a[p].cnt); 
    }
    //2.左子树siz>rak,说明排名为rak的节点在左子树中
    //3.左子树的siz+p点的cnt>rank,而且左子树的siz<rak,说明排名为rak的就是p点的val
    //4.其他就,递归处理右子树,注意要减去左子树siz和p点的重复值
  • 前駆体/後継者を探す:
    前駆体はvalの最大値の値よりも小さい場合、valの後継者は**最小値よりも大きくなっています

    int GetPre(int val){
      int ans=1;
      int p=root;
      while(p){
          if(a[p].val==val){
              if(a[p].l>0){
                  p=a[p].l;
                  while(a[p].r>0) p=a[p].r;
                  ans=p;
              }
              break;
          }
          if(a[p].val<val&&a[p].val>a[ans].val) ans=p;
          p= val<a[p].val ? a[p].l : a[p].r;
      }
      return a[ans].val;
    }
    int GetNext(int val){
      int ans=2;
      int p=root;
      while(p){
          if(val==a[p].val){
              if(a[p].r){
                  p=a[p].r;
                  while(a[p].l>0)p=a[p].l;
                  ans=p;
              }
              break;
          }
          if(a[p].val>val&&a[p].val<a[ans].val) ans=p;
          p= val<a[p].val ? a[p].l : a[p].r;
      }
      return a[ans].val;
    }

完全なコード:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MA=1e5+5;
const int INF=0x3f3f3f3f;

struct Treap
{
    int l,r;
    int val,dat;    //val:权值,dat:随机值,用来判断左右旋
    int cnt,siz;    //cnt:记录这个权值的重复次数,siz:子树大小
}a[MA];
int tot,n,root;

int New(int val){
    a[++tot].val=val;
    a[tot].siz=a[tot].cnt=1;
    a[tot].dat=rand();
    return tot;
}

void Updata(int p){
    a[p].siz=a[a[p].l].siz+a[a[p].r].siz+a[p].cnt;
}

void Build(){
    New(-INF),New(INF);
    root=1,a[1].r=2;
    Updata(root);
}

void zig(int &p){
    int q=a[p].l;
    a[p].l=a[q].r,a[q].r=p;
    p=q;
    Updata(a[p].r);
    Updata(p);
}

void zag(int &p){
    int q=a[p].r;
    a[p].r=a[q].l,a[q].l=p;
    p=q;
    Updata(a[p].l);
    Updata(p);
}

void Insert(int &p,int val){
    if(!p){
        p=New(val);
        return;
    }
    if(val==a[p].val){
        a[p].cnt++,Updata(p);
        return;
    }
    if(val<a[p].val){
        Insert(a[p].l,val);
        if(a[p].dat<a[a[p].l].dat) zig(p);
    }
    else{
        Insert(a[p].r,val);
        if(a[p].dat<a[a[p].r].dat) zag(p);
    }
    Updata(p);
}

void Remove(int &p,int val){
    if(p==0) return;
    if(val==a[p].val){
        if(a[p].cnt>1){     //val这个值有重复,直接减少cnt即可
            a[p].cnt--,Updata(p);
            return;
        }
        if(a[p].l||a[p].r){     //p有子树,不是叶子
            if(a[p].r==0||a[a[p].l].dat > a[a[p].r].dat) zig(p),Remove(a[p].r,val);     //左子树长于右子树,向右旋
            else zag(p),Remove(a[p].l,val);
            Updata(p);
        }
        else p=0;               //p是叶子直接删除
        return;
    }
    if(val<a[p].val) Remove(a[p].l,val);
    else Remove(a[p].r,val);
    Updata(p);

}

int GetRankByVal(int p,int val){
    if(p==0) return 0;
    if(val==a[p].val) return a[a[p].l].siz+1;
    else if(val<a[p].val) return GetRankByVal(a[p].l,val);
    return GetRankByVal(a[p].r,val)+a[a[p].l].siz+a[p].cnt;
}

int GetvalByRank(int p,int rak){
    if(p==0) return INF;
    if(a[a[p].l].siz>=rak) return GetvalByRank(a[p].l,rak); //左子树siz>rak,说明排名为rak的节点在左子树中
    if(a[a[p].l].siz+a[p].cnt>=rak) return a[p].val;        //左子树的siz+p点的cnt>rank,而且左子树的siz<rak,说明排名为rak的就是p点的val
    return GetvalByRank(a[p].r,rak-a[a[p].l].siz-a[p].cnt); //其他就,递归处理右子树,注意要减去左子树siz和p点的重复值
}

int GetPre(int val){
    int ans=1;
    int p=root;
    while(p){       //子树为处理完
        if(a[p].val==val){      //找到val的节点
            if(a[p].l>0){       //如果p有左子树,那就让p->左子树,然后一直向右子树移动,最后得到的p就是小于val的最大值
                p=a[p].l;
                while(a[p].r>0) p=a[p].r;
                ans=p;
            }
            break;
        }
        if(a[p].val<val&&a[p].val>a[ans].val) ans=p;    //用p的值更新ans,找小于val的最大值
        p= val<a[p].val ? a[p].l : a[p].r;              //递归合适的子树
    }
    return a[ans].val;
}

int GetNext(int val){
    int ans=2;
    int p=root;
    while(p){
        if(val==a[p].val){
            if(a[p].r){
                p=a[p].r;
                while(a[p].l>0)p=a[p].l;
                ans=p;
            }
            break;
        }
        if(a[p].val>val&&a[p].val<a[ans].val) ans=p;
        p= val<a[p].val ? a[p].l : a[p].r;
    }
    return a[ans].val;
}


int main()
{
    Build();
    scanf("%d",&n);
    while(n--){
        int opt,x;
        scanf("%d%d",&opt,&x);
        if(opt==1) Insert(root,x);
        else if(opt==2) Remove(root,x);
        else if(opt==3) printf("%d\n",GetRankByVal(root,x)-1);
        else if(opt==4) printf("%d\n",GetvalByRank(root,x+1));
        else if(opt==5) printf("%d\n",GetPre(x));
        else if(opt==6) printf("%d\n",GetNext(x));
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/A-sc/p/12244363.html