平衡树 替罪羊树

//平衡树 替罪羊树
//不进行旋转 当左右子树重量相差过大(通常以3:1为界)就把树拍扁重构 
//重构即以最中心节点为根节点 二分建树 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define lim 0.75//拍扁重构的标准 
using namespace std;
int n,root,size,cnt;
int goat,flat[1000001];//需要拍扁重构的节点,拍扁重构时暂存的数组 
struct uio{
    int son[2],val,siz,ava;//左右儿子,权值,子树大小+自己大小,未被删除的子树大小 
    bool exist;//标记是否被删除 
}scg[1000001];
bool check(int now)//判断是否拍扁 
{
    if((double)scg[now].ava*lim<=(double)max(scg[scg[now].son[0]].ava,scg[scg[now].son[1]].ava))
    //这是说 如果此节点未被删除的节点总数的3/4比任意一棵子树未被删除的节点数少(即:一棵子树未被删除的节点数是另一棵的3倍还多) 
        return true;//需要拍扁 
    return false;//不用拍扁 
}
void dfs(int now)//中序遍历,找出需要参与重构的节点 
{
    if(!now)
        return;
    dfs(scg[now].son[0]);
    if(scg[now].exist)
        flat[++cnt]=now;
    dfs(scg[now].son[1]);
}
void build(int l,int r,int &now)//构造过程 
{
    int mid=(l+r)/2;
    now=flat[mid];
    if(l==r)
    {
        scg[now].son[0]=scg[now].son[1]=0;
        scg[now].siz=scg[now].ava=1;
        return;
    }
    if(l<mid)
        build(l,mid-1,scg[now].son[0]);
    else scg[now].son[0]=0;
    build(mid+1,r,scg[now].son[1]);
    scg[now].siz=scg[scg[now].son[0]].siz+scg[scg[now].son[1]].siz+1;
    scg[now].ava=scg[scg[now].son[0]].ava+scg[scg[now].son[1]].ava+1;
}
void rebuild(int &now)//重构 
{
    cnt=0;
    dfs(now);
    if(cnt)
        build(1,cnt,now);
    else now=0;
}
int get_no(int k)
{
    int now=root,ans=1;
    while(now)
    {
        if(scg[now].val>=k)
            now=scg[now].son[0];
        else
        {
            ans+=scg[scg[now].son[0]].ava+scg[now].exist;
            now=scg[now].son[1];
        }
    }
    return ans;
} 
void insert(int &now,int k)
{
    if(!now)
    {
        now=++size;
        scg[now].val=k;
        scg[now].siz=scg[now].ava=1;
        scg[now].exist=true;
        scg[now].son[0]=scg[now].son[1]=0;
        return;
    }
    scg[now].siz++;
    scg[now].ava++;
    if(scg[now].val>=k)
        insert(scg[now].son[0],k);
    else insert(scg[now].son[1],k);
    if(!check(now))//此节点不需要重构 
    {//注:此处大括号不可去除!!!否则100行else会对应92行if而不是90行if导致多次拍扁重构! 
        if(goat)//子节点中有满足重构条件的点 
        {
            if(scg[now].son[0]==goat)
                rebuild(scg[now].son[0]);
            else rebuild(scg[now].son[1]);
            goat=0;
        }
    }//注:此处大括号不可去除!!!否则100行else会对应92行if而不是90行if导致多次拍扁重构! 
    else goat=now;//此节点需要重构,则继续记录 
}
void del_pos(int &now,int k)
{
    if(scg[now].exist&&scg[scg[now].son[0]].ava+1==k)
    {
        scg[now].exist=false;
        scg[now].ava--;
        return;
    }
    scg[now].ava--;
    if(scg[scg[now].son[0]].ava+scg[now].exist>=k)
        del_pos(scg[now].son[0],k);
    else del_pos(scg[now].son[1],k-scg[scg[now].son[0]].ava-scg[now].exist);
}
void del_val(int k)
{
    del_pos(root,get_no(k));
    if((double)scg[root].siz*lim>=scg[root].ava)//若根节点被删除的节点过多(即:超过总结点的1/4) 
        rebuild(root);//重构根节点 
}
int get_num(int k)
{
    int now=root;
    while(now)
    {
        if(scg[now].exist&&scg[scg[now].son[0]].ava+1==k)
            return scg[now].val;
        else if(scg[scg[now].son[0]].ava>=k)
            now=scg[now].son[0];
        else
        {
            k-=scg[scg[now].son[0]].ava+scg[now].exist;
            now=scg[now].son[1];
        }
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        if(u==1)
            insert(root,v);
        if(u==2)
            del_val(v);
        if(u==3)
            printf("%d\n",get_no(v));
        if(u==4)
            printf("%d\n",get_num(v));
        if(u==5)
            printf("%d\n",get_num(get_no(v)-1));
            //前驱:即k的位置的前一位 
        if(u==6)
            printf("%d\n",get_num(get_no(v+1)));
            //后继:即比k大的第一个数的位置 不能直接加一是因为k可能不止一个 
    }
     return 0;
}

猜你喜欢

转载自www.cnblogs.com/water-radish/p/9280885.html