bzoj:1503[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

题解

由于加减工资是对所有人有效,所以可以通过设置一个基准值,使得实际工资=基准值+相对工资,加减工资时只用改变基准即可。记得每次减工资以后看一看有几个人离开并记录。

因为要找第k大的数,所以左子树>根节点>右子树(节点权值),这样操作比较方便。

删除操作比较简单,找到k大于的那一部分,将其连同子树全部删掉,然后把另外大于等于它的一边做根即可。

(特别鸣谢wahaha大佬%%%)

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #define maxn 100010
  6 using namespace std;
  7 int n,root,ans,Std,cnt;
  8 struct treap{
  9     int lc,rc,key,pri,siz,val;
 10 }a[maxn];
 11 void pushup(int o){a[o].siz=a[a[o].lc].siz+a[a[o].rc].siz+a[o].val;}
 12 void lturn(int &o)
 13 {
 14     int t=a[o].rc;
 15     a[o].rc=a[t].lc;
 16     a[t].lc=o;
 17     a[t].siz=a[o].siz;
 18     pushup(o);
 19     o=t;
 20     return ;
 21 }
 22 void rturn(int &o)
 23 {
 24     int t=a[o].lc;
 25     a[o].lc=a[t].rc;
 26     a[t].rc=o;
 27     a[t].siz=a[o].siz;
 28     pushup(o);
 29     o=t;
 30     return ;
 31 }
 32 void insert(int &o,int x)
 33 {
 34     if(!o)
 35     {
 36         o=++cnt;
 37         a[o]=(treap){0,0,x,rand(),1,1};
 38         return ;
 39     }
 40     a[o].siz++;
 41     if(a[o].key==x) a[o].val++;
 42     else if(x>a[o].key)
 43     {
 44         insert(a[o].lc,x);
 45         if(a[a[o].lc].pri>a[o].pri)rturn(o);
 46     }
 47     else
 48     {
 49         insert(a[o].rc,x);
 50         if(a[a[o].rc].pri>a[o].pri)lturn(o);
 51     }
 52     return ;
 53 }
 54 void del(int &o,int x)
 55 {
 56     if(!o)return ;
 57     if(x<=a[o].key)
 58     {
 59         del(a[o].rc,x);
 60         pushup(o);
 61     }
 62     else 
 63     {
 64         ans+=a[a[o].rc].siz+a[o].val;
 65         a[o].rc=0;
 66         o=a[o].lc;
 67         del(o,x);
 68         pushup(o);
 69     }
 70     return ;
 71 }
 72 int que_num(int o,int x)
 73 {
 74     if(!o)return 0;
 75     if(x<=a[a[o].lc].siz)return que_num(a[o].lc,x);
 76     if(x<=a[a[o].lc].siz+a[o].val)return o;
 77     return que_num(a[o].rc,x-a[o].val-a[a[o].lc].siz);
 78 }
 79 int main()
 80 {
 81     int lim;
 82     scanf("%d%d",&n,&lim);
 83     srand(n);
 84     char str[3];int k;
 85     for(int i=1 ; i<=n ; ++i )
 86     {
 87         scanf("%s%d",str,&k);
 88         if(str[0]=='I')
 89         {
 90             if(k>=lim)insert(root,k-Std);
 91         }    
 92         else if(str[0]=='A')Std+=k;
 93         else if(str[0]=='S')
 94         {
 95             Std-=k;
 96             del(root,lim-Std);
 97         }
 98         if(str[0]=='F')
 99         {
100             k=que_num(root,k);
101             if(!k)printf("-1
");
102             else printf("%d
",a[k].key+Std);
103         }
104     }
105     printf("%d",ans);
106     return 0;
107 }
原文地址:https://www.cnblogs.com/fujudge/p/7561321.html