0x46 Blue Book exercise: general balanced tree

Treap / balanced binary tree


Blue Book Problem: General balanced tree

This question is a balanced tree template problem, you can use multiple solutions, where the most simple Treap, the following briefly about the idea of ​​various operations

  • Add :
    When you want to add a value to be added is determined whether p is the root node in the subtree is empty, add the new node is empty: New (val). Of course balanced tree, when adding a new node, the child node dat becomes larger than a [p] .dat, to rotate, the code handedness see, easy to understand.

    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);
    }
  • Delete:
    balanced tree deletion easier, it is to be deleted node spins to the leaves, and then deleted. See Code

    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);
    
    }
  • Output a value of ranking:
    the nature of the balanced binary tree, the leftmost minimal value, then I know that if the left subtree siz p, then p ranking is a [a [p] .l] .siz + 1, according to this a little. If val <a [p] .val, val described in the left subtree, recursively process the left subtree. When val> a [p] .val, when the return value and repetition frequency p and p siz left subtree cnt This is due to the recursive right subtree return value is indicated in the right val recursive right subtree subtree ranking, but easy to know, val larger than the left subtree and p 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;
    }
    
  • An output value ranking:
    this look at the code.

    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点的重复值
  • Find precursors / successors:
    precursor is smaller than the maximum value of val, val successor is larger than the minimum **

    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;
    }

Complete code:

#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;
}

Guess you like

Origin www.cnblogs.com/A-sc/p/12244363.html