洛谷 P3369 【模板】普通平衡树 ——替罪羊树

This way

题意:

上边的按钮。
大意是让你支持添加,删除,查询第k大,查询x的排名,查询第一个比x小的数,第一个比x大的数。

题解:

如果不是要求强制在线的话,权值线段树就可以支持所有的以上操作。
其实我感觉它就存一个模板就好了,重心还是放在splay上。
它大概为的是防止splay的增删改查操作的时间复杂度退化。当一个子树过于不平衡的时候重铸这棵子树。时间复杂度大概是 n l o g n nlogn nlogn多一点。
只保存一个模板,模板出处:This way

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,st,rt,cnt,tot,cur[N+5],Void[N+5];
const double alpha=0.75;//不平衡度系数
struct Scapegoat
{
    int Son[2],Exist,Val,Size,Fac;
}node[N+5];
inline char tc()
{
    static char ff[N],*A=ff,*B=ff;
    return A==B&&(B=(A=ff)+fread(ff,1,N,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0;int f=1;char ch;
    while(!isdigit(ch=tc())) if(ch=='-') f=-1;
    while(x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
    x*=f;
}
inline void write(int x)
{
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
inline void PushUp(int x)
{
    node[x].Size=node[node[x].Son[0]].Size+node[node[x].Son[1]].Size+1,node[x].Fac=node[node[x].Son[0]].Fac+node[node[x].Son[1]].Fac+1;
}
inline void Init()
{
    tot=0;
    for(register int i=N-1;i;--i) Void[++tot]=i;
}
inline bool balance(int x)
{
    return (double)node[x].Fac*alpha>(double)max(node[node[x].Son[0]].Fac,node[node[x].Son[1]].Fac);
}
inline void Build(int x)
{
    node[x].Son[0]=node[x].Son[1]=0,node[x].Size=node[x].Fac=1;
}
inline void Traversal(int x)
{
    if(!x) return;
    Traversal(node[x].Son[0]);
    if(node[x].Exist) cur[++cnt]=x;
    else Void[++tot]=x;
    Traversal(node[x].Son[1]);
}
inline void SetUp(int l,int r,int &x)
{
    int mid=l+r>>1;x=cur[mid];
    if(l==r)
    {
        Build(x);
        return;
    }
    if(l<mid) SetUp(l,mid-1,node[x].Son[0]);
    else node[x].Son[0]=0;
    SetUp(mid+1,r,node[x].Son[1]),PushUp(x);
}
inline void ReBuild(int &x)
{
    cnt=0,Traversal(x);
    if(cnt) SetUp(1,cnt,x);
    else x=0;
}
inline void check(int x,int val)
{
    int s=val<=node[x].Val?0:1;
    while(node[x].Son[s])
    {
        if(!balance(node[x].Son[s]))
        {
            ReBuild(node[x].Son[s]);
            return;
        }
        x=node[x].Son[s],s=val<=node[x].Val?0:1;
    }
}
inline void Insert(int &x,int val)
{
    if(!x)
    {
        x=Void[tot--],node[x].Val=val,node[x].Exist=1,Build(x);
        return;
    }
    ++node[x].Size,++node[x].Fac;
    if(val<=node[x].Val) Insert(node[x].Son[0],val);
    else Insert(node[x].Son[1],val);
}
inline int get_rank(int v)
{
    int x=rt,rk=1;
    while(x)
    {
        if(node[x].Val>=v) x=node[x].Son[0];
        else rk+=node[node[x].Son[0]].Fac+node[x].Exist,x=node[x].Son[1];
    }
    return rk;
}
inline int get_val(int rk)
{
    int x=rt;
    while(x)
    {
        if(node[x].Exist&&node[node[x].Son[0]].Fac+1==rk) return node[x].Val;
        else if(node[node[x].Son[0]].Fac>=rk) x=node[x].Son[0];
        else rk-=node[x].Exist+node[node[x].Son[0]].Fac,x=node[x].Son[1];
    }
}
inline void Delete(int &x,int rk)
{
    if(node[x].Exist&&!((node[node[x].Son[0]].Fac+1)^rk))
    {
        node[x].Exist=0,--node[x].Fac;
        return;
    }
    --node[x].Fac;
    if(node[node[x].Son[0]].Fac+node[x].Exist>=rk) Delete(node[x].Son[0],rk);
    else Delete(node[x].Son[1],rk-node[x].Exist-node[node[x].Son[0]].Fac);
}
inline void del(int v)
{
    Delete(rt,get_rank(v));
    if((double)node[rt].Size*alpha>(double)node[rt].Fac) ReBuild(rt);
}
int main()
{
    Init();
    scanf("%d",&n);
    while(n--)
    {
        int op,x;
        scanf("%d%d",&op,&x);
        if(op==1)
            Insert(rt,x),check(rt,x);
        else if(op==2)
            del(x);
        else if(op==3)
            printf("%d\n",get_rank(x));
        else if(op==4)
            printf("%d\n",get_val(x));
        else if(op==5)
            printf("%d\n",get_val(get_rank(x)-1));
        else
            printf("%d\n",get_val(get_rank(x+1)));
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值