替罪羊树模版

替罪羊树真的贼TM长。。。。

洛谷,普通平衡树

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 1e5+5;
const double alpha = 0.75;
struct node{
  int l,r,val;
  int size,fact;
  ///子树大小,实际大小
  bool exist;
}tzy[maxn];
int cnt,root;
///新建节点
void newnode(int &now,int val)
{
    now=++cnt;
    tzy[now].val=val;
    tzy[now].size=tzy[now].fact=1;
    tzy[now].exist=true;
}
///判断是否平衡
bool imbalance(int now)
{
    ///左右子树的size中最大的一个的大小大于节点大小*平衡因子
    ///被删掉的节点个数大于0.3
    if(max(tzy[tzy[now].l].size,tzy[tzy[now].r].size)>tzy[now].size*alpha
       || tzy[now].size-tzy[now].fact>tzy[now].size*0.3)
        return true;
     else
        return false;
}
vector<int>v;
///中序列遍历
void idr(int now)
{
    if (!now)return;
    idr(tzy[now].l);
    if (tzy[now].exist)
        v.push_back(now);
    idr(tzy[now].r);
}
///拎起来
void lift(int l,int r,int &now)
{
    ///拎起来到叶子节点
    if (l==r)
    {
        now=v[l];
        ///变成叶子节点状态
        tzy[now].l=tzy[now].r=0;
        tzy[now].size=tzy[now].fact=1;
        return;
    }
    int m=(l+r)>>1;
    ///防止值相同跑到左边去
    while(m && l<m && tzy[v[m]].val==tzy[v[m-1]].val)
        m--;
    now=v[m];
    if(l<m)lift(l,m-1,tzy[now].l);
    else tzy[now].l=0;
    ///向下取整,可以直接取
    lift(m+1,r,tzy[now].r);
    tzy[now].size=tzy[tzy[now].l].size+tzy[tzy[now].r].size+1;
    tzy[now].fact=tzy[tzy[now].l].fact+tzy[tzy[now].r].fact+1;
}
void update(int now,int end)
{
    if(!now)return;
    if (tzy[end].val<tzy[now].val)
        update(tzy[now].l,end);
    else update(tzy[now].r,end);
    tzy[now].size=tzy[tzy[now].l].size+tzy[tzy[now].r].size+1;
}
///暴力重构
///进行中序遍历拉成直线,挂起来,然后分治拎起来
void rebuild(int &now)
{
    v.clear();
    idr(now);
    if (v.empty())
    {
        now=0;
        return;
    }
    lift(0,v.size()-1,now);
}
///检查是否需要重构
///不能从下往上找
///重构条件----当前节点的左子树或者右子树的大小大于当前节点的大小乘以一个平衡因子alpha
void check(int &now,int end)
{
    if (now==end)return;
    ///判断当前节点是否平衡
    if (imbalance(now))
    {
        ///重构
        rebuild(now);
        ///往上更新
        update(root,now);
        return ;
    }
    ///终点在当前节点的左子树
    if (tzy[end].val<tzy[now].val)
        check(tzy[now].l,end);
    else
        check(tzy[now].r,end);
}
///插入操作
void ins(int &now,int val){
    if (!now)//当前节点不存在
    {
        newnode(now,val);;
        ///是否需要重构
        check(root,now);
        return;
    }
    tzy[now].size++;
    tzy[now].fact++;
    ///小于左插,大于右插
    if(val<tzy[now].val)
        ins(tzy[now].l,val);
    else
        ins(tzy[now].r,val);
}
///惰性删除
void del(int now,int val)
{
    ///当前节点存在,并且当前节点的值等于当前需要删除的值
    if (tzy[now].exist && tzy[now].val==val)
    {
        tzy[now].exist=false;
        tzy[now].fact--;
        ///删除后是否平衡
        check(root,now);
        return;
    }
    tzy[now].fact--;
    if (val<tzy[now].val)
        del(tzy[now].l,val);
    else
        del(tzy[now].r,val);
}
int getrank(int val)
{
    int now=root,rank=1;
    while(now)
    {
        ///如果查找的值小于等于当前节点的值,往左找
        if (val<=tzy[now].val)
            now=tzy[now].l;
        else
        {
            ///把左子树以及当前节点的值算进去
           rank+=tzy[now].exist+tzy[tzy[now].l].fact;
           now=tzy[now].r;
        }
     //   cout<<tzy[now].val<<" "<<rank<<endl;
    }
   // cout<<endl;
    return rank;
}
int getnum(int rank)
{
    int now=root;
    while(now)
    {
        ///当前节点左子树+当前节点是否存在为rank,那么退出
        if(tzy[now].exist && tzy[tzy[now].l].fact+tzy[now].exist==rank)
            break;
        else if(tzy[tzy[now].l].fact>=rank)
            now=tzy[now].l;
        else
        {
            rank-=tzy[tzy[now].l].fact+tzy[now].exist;
            now=tzy[now].r;
        }
    }
    return tzy[now].val;
}
int main(){
   int t;
   int op,x;
   scanf("%d",&t);
   cnt=0;
   while(t--){
      scanf("%d%d",&op,&x);
      if (op==1){
        ins(root,x);
      }else if (op==2){
        del(root,x);
      }else if (op==3){
        printf("%d\n",getrank(x));
      }else if (op==4){
        printf("%d\n",getnum(x));
      }else if (op==5){
        ///查询的是x的排名-1的数是什么
        printf("%d\n",getnum(getrank(x)-1));
      }else {
        ///查询的是小于等于x+1的数的个数
        ///因为我们在查找的时候强行把这个值rank值自动设置为1
        ///那么就强行认为这个数是rank1,然后查询比这个数小的个数
        printf("%d\n",getnum(getrank(x+1)));
      }
   }
   return 0;
}
/*
5
1 2
1 4
1 6
6 4
*/

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值