您的位置:首页 > 其它

【例题】【Splay】NKOJ1921 郁闷的出纳员

2016-12-03 21:31 218 查看
NKOJ1921 郁闷的出纳员

时间限制 : 10000 MS 空间限制 : 65536 KB

问题描述

OIER公司是一家大型专业化软件公司,有着数以万计的员工。作为一名出纳员,我的任务之一便是统计每位员工的工资。这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资。如果他心情好,就可能把每位员工的工资加上一个相同的量。反之,如果心情不好,就可能把他们的工资扣除一个相同的量。我真不知道除了调工资他还做什么其它事情。

   工资的频繁调整很让员工反感,尤其是集体扣除工资的时候,一旦某位员工发现自己的工资已经低于了合同规定的工资下界,他就会立刻气愤地离开公司,并且再也不会回来了。每位员工的工资下界都是统一规定的。每当一个人离开公司,我就要从电脑中把他的工资档案删去,同样,每当公司招聘了一位新员工,我就得为他新建一个工资档案。

   老板经常到我这边来询问工资情况,他并不问具体某位员工的工资情况,而是问现在工资第k多的员工拿多少工资。每当这时,我就不得不对数万个员工进行一次漫长的排序,然后告诉他答案。

   好了,现在你已经对我的工作了解不少了。正如你猜的那样,我想请你编一个工资统计程序。怎么样,不是很困难吧?

输入格式

第一行有两个非负整数n和min。n表示下面有多少条命令,min表示工资下界。

   接下来的n行,每行表示一条命令。命令可以是以下四种之一:

I命令 I_k 新建一个工资档案,初始工资为k。如果某员工的初始工资低于工资下界,他将立刻离开公司。

A命令 A_k 把每位员工的工资加上k

S命令 S_k 把每位员工的工资扣除k

F命令 F_k 查询第k多的工资

_(下划线)表示一个空格,I命令、A命令、S命令中的k是一个非负整数,F命令中的k是一个正整数。

在初始时,可以认为公司里一个员工也没有。

输出格式

输出文件的行数为F命令的条数加一。

对于每条F命令,你的程序要输出一行,仅包含一个整数,为当前工资第k多的员工所拿的工资数,如果k大于目前员工的数目,则输出-1。

输出文件的最后一行包含一个整数,为离开公司的员工的总数。

样例输入

9 10

I 60

I 70

S 50

F 2

I 30

S 15

A 5

F 1

F 2

样例输出

10

20

-1

2

提示

I命令的条数不超过100000

A命令和S命令的总条数不超过100

F命令的条数不超过100000

每次工资调整的调整量不超过1000

新员工的工资不超过100000

来源 NOI2004

思路:

设实际工资=存储的工资-del

(1)、加人:特判后insert,好像“如果某员工的初始工资低于工资下界,他将立刻离开公司”并不算作离开公司

(2)、加工资:将del减小

(3)、减工资:将del增加。

删除操作:找到第一个刚刚超过界限的人做根,将根的左子改为0,更新根的size。注意所有人都离开时特殊处理

(4)、找第k大:直接找

#include<cstdio>
#include<iostream>
using namespace std;
const int need=100004;
typedef int int_[need];

//.............................................
inline void inc(char &d)
{
d=getchar();while(d==' '||d==10) d=getchar();
}
inline void in_(int &d)
{
char t=getchar();bool mark=0;
while(t<'0'||t>'9') {if(t=='-') mark=1;t=getchar();}
for(d=0;!(t<'0'||t>'9');t=getchar()) d=(d<<1)+(d<<3)+t-'0';if(mark) d=-d;
}
inline void out_(int x)
{
if(x<0) {x=-x;putchar('-');}
if(x>=10) out_(x/10);
putchar(x%10+'0');
}
//.............................................
int k,n,del,ans;
int root,tot;
int_ fa,ls,rs,si,val;

#define NBHB(x) si[x]=si[ls[x]]+si[rs[x]]+1

inline void sr(int x)
{
int y=fa[x],z=fa[y];
ls[z]==y ? ls[z]=x :rs[z]=x; fa[x]=z;
ls[y]=rs[x]; fa[rs[x]]=y;
rs[x]=y; fa[y]=x;
NBHB(y),NBHB(x);
}
inline void sl(int x)
{
int y=fa[x],z=fa[y];
ls[z]==y ? ls[z]=x :rs[z]=x; fa[x]=z;
rs[y]=ls[x]; fa[ls[x]]=y;
ls[x]=y; fa[y]=x;
NBHB(y),NBHB(x);
}
inline void splay(int x)
{
int y;
while(y=fa[x])
{
if(ls[y]==x) sr(x);
else sl(x);
}
root=x;
}
inline void insert(int d)
{
if(root==0)
{
val[root=1]=d;
si[1]=1;
ls[1]=rs[1]=fa[1]=0;
tot++;
return ;
}
tot++;
int p=root;
while(true)
{
if(d<val[p])
if(ls[p]) p=ls[p];
else {ls[p]=tot;break;}
else
if(rs[p]) p=rs[p];
else {rs[p]=tot;break;}
}
si[tot]=1;fa[tot]=p;val[tot]=d;
splay(tot);
}
//.............................................
int d;

int find(int p)//找第一个大于等于d的节点
{
if(p==0) return -1;//上一个节点没有左右儿子,返回-1
if(val[p]<d) return find(rs[p]);
if(val[p]>=d)
{
int kk=find(ls[p]);
if(kk!=-1&&val[kk]>=d) return kk;
else return p;
}
}
void deal(int dd)
{
d=dd;
int kk=find(root);
if(kk==-1)
{
ans+=si[root];
root=0;
}
else
{
splay(kk);
ans+=si[ls[kk]];
ls[kk]=0,si[kk]=si[rs[kk]]+1;
}
}
int getk(int k)
{
if(k>si[root]) return -1;
int p=root;
while(true)
{
if(si[rs[p]]>=k) p=rs[p];
else if(si[rs[p]]==k-1) return val[p];
else {k-=si[rs[p]]+1;p=ls[p];}
}
}
//.............................................

int main()
{
scanf("%d%d",&n,&k);
char c;int b;
for(int i=1,kk;i<=n;i++)
{
inc(c);in_(b);
if(c=='I')
{
if(b>=k)insert(b+del);
}
else if(c=='A') del-=b;
else if(c=='S')
{
del+=b;
deal(k+del);
}
else
{
kk=getk(b);
out_(kk==-1 ? kk :kk-del),putchar(10);
}
}
out_(ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: