替罪羊树

替罪羊树

一 定义

替罪羊树是计算机科学中,一种基于部分重建的自平衡二叉搜索树。在替罪羊树上,插入或删除节点的平摊最坏时间复杂度是O(log n),搜索节点的最坏时间复杂度是O(log n)

(非常暴力,一言不合拍扁重建)

二 思路

插入 

和普通平衡树没啥区别...

void insert(node* &now,int x)
{
  if(now==null)
  {
    now=new node;
    now->val=x;
    now->size=1;
    now->del=false;
    now->l=now->r=null;
    return ;
  }
  ++now->size;
  if(x<=now->val)
    insert(now->l,x);
  else
    insert(now->r,x);
  if(now->bad())
    rebuild(now);
  return ;
}

删除

替罪羊树的删除不是真正意义上的删除,而是给这个节点打标记,在重构时不将它加入树中。

void erase(node *now,int rk)
{
  if(!now->del && rk==now->l->size+1)
  {
    now->del=1;
    --now->size;
    return;
  }
  --now->size;
  if(rk<=now->l->size+!now->del)
    erase(now->l,rk);
  else
    erase(now->r,rk-now->l->size-!now->del);
}

判断重建

定义一个平衡因子alpha,如果左右子树大小大于整棵树的大小*alpha,就将这棵子树拍扁重建

struct node
{
  node* l;
  node* r;
  int val;
  int size;
  bool del;

  bool bad()         //判断是否需要重建
  {
    if(l->size>size*alpha+5||r->size>size*alpha+5)
      return true;
    else
      return false;
  }

  void push_up()
  {
    size=l->size+r->size+!del;
    return ;
  }

};

void dfs(vector<node*> &v,node* now)
{
  if(now==null)
    return ;
  dfs(v,now->l);
  if(!now->del)
    v.push_back(now);
  dfs(v,now->r);
  if(now->del)
    delete now;
  return ;
}

node* build(vector<node*> &v,int l,int r)
{
  if(l>=r)
    return null;
  int mid=(l+r)>>1;
  node* now=v[mid];
  now->l=build(v,l,mid);
  now->r=build(v,mid+1,r);
  now->push_up();
  return now;
}

void rebuild(node* &now)
{
  vector<node*> v;
  dfs(v,now);
  now=build(v,0,v.size());
  return ;
}

(其实还应该判断已经删除个数是否大于整棵树的一半,如果是,就将这棵子树拍扁重建(然而我忘写了...))

查找某排名的数

int kth(node* now,int x)
{
  while(now!=null)
  {
    if(now->l->size+1==x&&!now->del)
      return now->val;
    if(now->l->size>=x)
      now=now->l;
    else
    {
      x-=now->l->size+!now->del;
      now=now->r;
    }
  }
}

查找某数的排名

int rank(node* now,int x)
{
  int ans=1;
  while(now!=null)
  {
    if(now->val>=x)
      now=now->l;
    else
    {
      ans=ans+now->l->size+!now->del;
      now=now->r;
    }
  }
  return ans;
}

查找前驱

kth(root,rank(root,x)-1)

查找后继

kth(root,rank(root,x+1))

lg 3369

#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;

const double alpha=0.7;

struct node
{
  node* l;
  node* r;
  int val;
  int size;
  bool del;

  bool bad()
  {
    if(l->size>size*alpha+5||r->size>size*alpha+5)
      return true;
    else
      return false;
  }

  void push_up()
  {
    size=l->size+r->size+!del;
    return ;
  }

};

node* null;
node* root;

void dfs(vector<node*> &v,node* now)
{
  if(now==null)
    return ;
  dfs(v,now->l);
  if(!now->del)
      v.push_back(now);
  dfs(v,now->r);
  if(now->del)
    delete now;
  return ;
}

node* build(vector<node*> &v,int l,int r)
{
  if(l>=r)
    return null;
  int mid=(l+r)>>1;
  node* now=v[mid];
  now->l=build(v,l,mid);
  now->r=build(v,mid+1,r);
  now->push_up();
  return now;
}

void rebuild(node* &now)
{
  vector<node*> v;
  dfs(v,now);
  now=build(v,0,v.size());
  return ;
}

void insert(node* &now,int x)
{
  if(now==null)
  {
    now=new node;
    now->val=x;
    now->size=1;
    now->del=false;
    now->l=now->r=null;
    return ;
  }
  ++now->size;
  if(x<=now->val)
    insert(now->l,x);
  else
    insert(now->r,x);
  if(now->bad())
    rebuild(now);
  return ;
}

void erase(node *now,int rk)
{
  if(!now->del && rk==now->l->size+1)
  {
    now->del=1;
    --now->size;
    return;
  }
  --now->size;
  if(rk<=now->l->size+!now->del)
    erase(now->l,rk);
  else
    erase(now->r,rk-now->l->size-!now->del);
}

int rank(node* now,int x)
{
  int ans=1;
  while(now!=null)
  {
    if(now->val>=x)
      now=now->l;
    else
    {
      ans=ans+now->l->size+!now->del;
      now=now->r;
    }
  }
  return ans;
}

int kth(node* now,int x)
{
  while(now!=null)
  {
    if(now->l->size+1==x&&!now->del)
      return now->val;
    if(now->l->size>=x)
      now=now->l;
    else
    {
      x-=now->l->size+!now->del;
      now=now->r;
    }
  }
}
int main()
{
  ios::sync_with_stdio(false);
  null=new node;
  root=null;
  int n;
  cin>>n;
  for(int i=1; i<=n; i++)
  {
    int opt,x;
    cin>>opt>>x;
    switch(opt)
    {
      case 1:
        insert(root,x);
        break;
      case 2:
              erase(root,rank(root,x));
        break;
      case 3:
        cout<<rank(root,x)<<endl;
        break;
      case 4:
        cout<<kth(root,x)<<endl;
        break;
      case 5:
        cout<<kth(root,rank(root,x)-1)<<endl;
        break;
      default:
        cout<<kth(root,rank(root,x+1))<<endl;
    }
  }
  return 0;
}
原文地址:https://www.cnblogs.com/Alarak26/p/9165931.html