HYSBZ - 1503——郁闷的出纳员 (Splay树)

本文深入探讨了Splay树的数据结构与算法实现,详细解释了如何通过Splay操作来保持树的平衡,以及如何利用Splay树进行数据的高效插入、查找和删除。文章通过一个具体的问题实例,展示了Splay树在处理动态数据集时的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1503

思路:把每次减工资或加工资都用一个变量add记下,加入一个员工时,给的初始工资是,因为树中的所有人都是默认工资加上                 add,把他加入树中时应该设工资为x-add。删减时应该删减树中工资少于lim-add的。

splay模板题:

#include<algorithm>
#include<string.h>
#include<stdio.h>
using namespace std;
struct node
{
    int v,f,ch[2],sum[2];
} T[100010];
int n,limit,x,add,root,tot,del;
char ch[5];
int new_node(int &root,int far,int k)
{
    root=++tot;
    T[root].ch[0]=T[root].ch[1]=0;
    T[root].sum[0]=T[root].sum[1]=0;
    T[root].f=far;
    T[root].v=k;
    return tot;
}
void rol(int r,int kind)//旋转
{
    int far=T[r].f,gar=T[far].f;
    T[far].ch[!kind]=T[r].ch[kind];
    T[T[r].ch[kind]].f=far;
    T[r].ch[kind]=far;
    T[far].f=r;
    T[gar].ch[T[gar].ch[1]==far]=r;
    T[r].f=gar;

    T[far].sum[!kind]=T[r].sum[kind];
    T[r].sum[kind]+=(T[far].sum[kind]+1);
    return ;
}
void splay(int r,int goal)//把r转到根节点
{
    while(T[r].f!=goal)
    {
        int far=T[r].f,gar=T[far].f;
        int kind=T[gar].ch[0]==far;
        if(gar==goal) rol(r,T[far].ch[0]==r);
        else
        {
            if(T[far].ch[kind]==r)
            {
                rol(r,!kind);
                rol(r,kind);
            }
            else
            {
                rol(far,kind);
                rol(r,kind);
            }
        }
    }
    root=r;
    return ;
}
int Insert(int k)//插入数据
{
    int r=root;
    while(T[r].ch[T[r].v<k])r=T[r].ch[T[r].v<k];
    new_node(T[r].ch[T[r].v<k],r,k);
    splay(T[r].ch[T[r].v<k],0);
    return 1;
}
int Find(int r,int lim)//找到最左边的与其相同的节点找不到返回-1
{
    while(r)
    {
        if(T[r].v==lim)
        {
            int p=Find(T[r].ch[0],lim);
            if(p==-1) return r;
            return p;
        }
        if(T[r].v>lim)
        {
            r=T[r].ch[0];
        }
        else
            r=T[r].ch[1];
    }
    return -1;
}
void Delete(int r,int lim)//删除节点
{
    int de=Find(r,lim-add);//如果有相同的,找到最左边的与它相同的
    if(de==-1)//如果没有相同的,加入一个节点与器相同,删除它左边的树,包括它
    {
        Insert(lim-add);
        del+=T[root].sum[0];
        int re=T[root].ch[1];
        T[re].f=0,root=re;
    }
    else//有相同的,把它变为根,删除它左边的点
    {
        splay(de,0);
        del+=T[de].sum[0];
        T[de].sum[0]=0;
        T[de].ch[0]=0;
    }
    return ;
}
//int Query(int r,int k)//遍历整颗树
//{
//    if(T[r].sum[0]+T[r].sum[1]<k) return -1;
//}
int Query(int r,int k)//查找第K大
{
    if(T[r].sum[0]+T[r].sum[1]+1<k) return -1;
    while(T[r].sum[1]!=k-1)
    {
        if(T[r].sum[1]<k-1) k-=T[r].sum[1]+1,r=T[r].ch[0];
        else r=T[r].ch[1];
    }
    return add+T[r].v;
}
void see(int r)//debug
{
    printf("%d\n",T[r].v);
    if(T[r].ch[1]) see(T[r].ch[1]);
    if(T[r].ch[0]) see(T[r].ch[0]);
}
int main()
{
    while(~scanf("%d%d",&n,&limit))
    {
        add=root=del=0;
        for(int i=1; i<=n; i++)
        {
            scanf("%s %d",ch,&x);
            if(ch[0]=='I'&&x>=limit) root==0?new_node(root,0,x-add):Insert(x-add);
            else if(ch[0]=='A') add+=x;
            else if(ch[0]=='S') add-=x,Delete(root,limit);
            else if(ch[0]=='F') printf("%d\n",Query(root,x));
//            see(root);
        }
        printf("%d\n",del);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值