[NOI2004]郁闷的出纳员

Description
OIER公司是一家大型专业化软件公司,有着数以万计的员工。作为一名出纳员,我的任务之一便是统计每位员工的工资。这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资。如果他心情好,就可能把每位员工的工资加上一个相同的量。反之,如果心情不好,就可能把他们的工资扣除一个相同的量。我真不知道除了调工资他还做什么其它事情。工资的频繁调整很让员工反感,尤其是集体扣除工资的时候,一旦某位员工发现自己的工资已经低于了合同规定的工资下界,他就会立刻气愤地离开公司,并且再也不会回来了。每位员工的工资下界都是统一规定的。每当一个人离开公司,我就要从电脑中把他的工资档案删去,同样,每当公司招聘了一位新员工,我就得为他新建一个工资档案。老板经常到我这边来询问工资情况,他并不问具体某位员工的工资情况,而是问现在工资第k多的员工拿多少工资。每当这时,我就不得不对数万个员工进行一次漫长的排序,然后告诉他答案。好了,现在你已经对我的工作了解不少了。正如你猜的那样,我想请你编一个工资统计程序。怎么样,不是很困难吧?

Input

Output
输出文件的行数为F命令的条数加一。对于每条F命令,你的程序要输出一行,仅包含一个整数,为当前工资第 k 多的员工所拿的工资数,如果k大于目前员工的数目,则输出 1 。输出文件的最后一行包含一个整数,为离开公司的员工的总数。

Sample Input
9 10
I 60
I 70
S 50
F 2
I 30
S 15
A 5
F 1
F 2

Sample Output
10
20
-1
2

HINT
I命令的条数不超过 100000
A命令和S命令的总条数不超过 100
F命令的条数不超过 100000
每次工资调整的调整量不超过 1000
新员工的工资不超过 100000

Source

思路
splay,每一次工资的增加和减少可以不对每一个值进行修改,而是记录一个全局变量,加入员工时只要加入实际工资减去增加量。底下会有注释。

代码

#include <cstdio>

const int maxn=100000;

int minn,leave,add;//leave是离开的人数,add是工资的增长量

struct splay_tree
{
  int root,tot,fa[maxn+10],son[2][maxn+10],size[maxn+10],val[maxn+10];

  inline int t(int x)
  {
    return son[1][fa[x]]==x;
  }

  inline int updata(int x)
  {
    size[x]=1;
    if(son[0][x])
      {
        size[x]+=size[son[0][x]];
      }
    if(son[1][x])
      {
        size[x]+=size[son[1][x]];
      }
    return 0;
  }

  inline int rotate(int x)
  {
    int k=t(x),f=fa[x];
    if(fa[f])
      {
        son[t(f)][fa[f]]=x;
      }
    fa[x]=fa[f];
    if(son[!k][x])
      {
        fa[son[!k][x]]=f;
      }
    son[k][f]=son[!k][x];
    fa[f]=x;
    son[!k][x]=f;
    updata(f);
    updata(x);
    return 0;
  }

  inline int splay(int x,int c)
  {
    while(fa[x]!=c)
      {
        int f=fa[x];
        if(fa[f]==c)
          {
            rotate(x);
          }
        else if(t(x)==t(f))
          {
            rotate(f);
            rotate(x);
          }
        else
          {
            rotate(x);
            rotate(x);
          }
      }
    if(!c)
      {
        root=x;
      }
    return 0;
  }

  inline int insert(int now,int x)
  {
    int p=(val[now]<x);
    if(!son[p][now])
      {
        son[p][now]=tot;
        fa[tot]=now;
        updata(now);
        return 0;
      }
    insert(son[p][now],x);
    updata(now);
    return 0;
  }

  inline int ins(int x)
  {
    if(x<minn)
      {
        return 0;
      }
    x-=add;
    ++tot;
    val[tot]=x;
    size[tot]=1;
    if(!root)
      {
        root=tot;
        return 0;
      }
    int now=root;
    if(now)
      {
        insert(now,x);
      }
    splay(tot,0);
    return 0;
  }

  int maintain(int x)//维护离开公司的人数
  {
    if(val[x]+add<minn)//这个人要离开公司了,把他的左子树和自己删掉
      {
        ++leave;
        if(son[0][x])
          {
            leave+=size[son[0][x]];
            son[0][x]=0;
          }
        if(son[1][x])
          {
            maintain(son[1][x]);
          }
        if(fa[x])
          {
            son[t(x)][fa[x]]=son[1][x];
            updata(fa[x]);//更新x的父亲,一定是在修复右儿子之后的
          }
        else
          {
            root=son[1][x];
          }
        if(son[1][x])
          {
            fa[son[1][x]]=fa[x];
          }
      }
    else//如果不要,那么在左子树中寻找要离开公司的人
      {
        if(son[0][x])
          {
            maintain(son[0][x]);
          }
        updata(x);//修复自己
      }
    return 0;
  }

  int kth(int x,int k)
  {
    if(size[x]<k)
      {
        return -1;
      }
    else if(size[son[1][x]]+1==k)
      {
        splay(x,0);
        return x;
      }
    else if(size[son[1][x]]+1<k)
      {
        return kth(son[0][x],k-size[son[1][x]]-1);
      }
    else
      {
        return kth(son[1][x],k);
      }
  }
};

splay_tree st;
int n,a;
char s[10];

int main()
{
  scanf("%d%d",&n,&minn);
  while(n--)
    {
      scanf("%s%d",s,&a);
      if(s[0]=='I')
        {
          st.ins(a);
        }
      else if(s[0]=='A')
        {
          add+=a;
        }
      else if(s[0]=='S')
        {
          add-=a;
          if(st.root)
            {
              st.maintain(st.root);
            }
        }
      else
        {
          if(st.size[st.root]<a)
            {
              puts("-1");
            }
          else
            {
              printf("%d\n",st.val[st.kth(st.root,a)]+add);
            }
        }
    }
  printf("%d\n",leave);
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值