1503: [NOI2004]郁闷的出纳员
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 3565 Solved: 1280
[ Submit][ Status][ Discuss]
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
I 60
I 70
S 50
F 2
I 30
S 15
A 5
F 1
F 2
Sample Output
10
20
-1
2
20
-1
2
HINT
I命令的条数不超过100000
A命令和S命令的总条数不超过100
F命令的条数不超过100000
每次工资调整的调整量不超过1000
新员工的工资不超过100000
Source
评测链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1503
解法:SBT。
这是一道sbt的裸题,当然,还可以用AVL、treap、线段树、树状数组解决。这里给出的是sbt的解法。
要注意的是,若给一个新人的工资低于工资下限,那么这个新人就不会成为公司员工,当然也不算做从公司离开的人。
对于sbt,我也是初学者,如果不会的,可以点击这个链接:http://pan.baidu.com/share/link?shareid=411971&uk=255096381&third=15,这里面是我初学sbt时所用的资料,并包含了本题的数据与多种标准解法(线段树、AVL等)。
代码:
#include<cstdio>
#include<algorithm>
#define maxn (100000+10)
using namespace std;
int l[maxn],r[maxn],s[maxn],p[maxn];
int root,sum,num,n,m,ans;
void init()
{
freopen("cashier.in","r",stdin);
freopen("cashier.out","w",stdout);
}
inline void right_rotate(int &t)
{
int k=l[t];
l[t]=r[k];
r[k]=t;
s[k]=s[t];
s[t]=s[l[t]]+s[r[t]]+1;
t=k;
}
inline void left_rotate(int &t)
{
int k=r[t];
r[t]=l[k];
l[k]=t;
s[k]=s[t];
s[t]=s[l[t]]+s[r[t]]+1;
t=k;
}
void maintain(int &t,bool flag)
{
if(flag)
if(s[l[l[t]]]>s[r[t]])
right_rotate(t);
else
if(s[r[l[t]]]>s[r[t]])
left_rotate(l[t]),right_rotate(t);
else
return;
else
if(s[r[r[t]]]>s[l[t]])
left_rotate(t);
else
if(s[l[r[t]]]>s[l[t]])
right_rotate(r[t]),left_rotate(t);
else
return;
maintain(l[t],1);
maintain(r[t],0);
maintain(t,1);
maintain(t,0);
}
void insert(int &k,int w)
{
if(k==0)
{
k=(++num);
s[k]=1,l[k]=r[k]=0,p[k]=w;
return;
}
s[k]++;
if(w<p[k])insert(l[k],w);
else insert(r[k],w);
maintain(k,w<p[k]);
}
void del(int &t)
{
if(t==0)return;
if(p[t]<m-sum)ans=ans+s[l[t]]+1,t=r[t],del(t);
else del(l[t]),s[t]=s[l[t]]+s[r[t]]+1;
}
void select(int t,int k)
{
if(s[r[t]]+1==k){printf("%d\n",p[t]+sum);return;}
if(k>s[r[t]]){select(l[t],k-s[r[t]]-1);return;}
select(r[t],k);
}
void work()
{
scanf("%d%d\n",&n,&m);
root=num=sum=ans=0;
int i,k;char op;
scanf("%c%d\n",&op,&k);
for(i=1;i<=n;scanf("%c%d\n",&op,&k),++i)
switch (op)
{
case 'I':if(k<m)break;
insert(root,k-sum);
break;
case 'A':sum+=k;
break;
case 'S':sum-=k,del(root);
break;
default :if(k>s[root]){printf("-1\n");break;}
select(root,k);
break;
}
printf("%d\n",ans);
}
int main()
{
init();
work();
return 0;
}