【例题】【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大:直接找
时间限制 : 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); }
相关文章推荐
- 【bzoj1503】[NOI2004]郁闷的出纳员 Splay
- 1503: [NOI2004]郁闷的出纳员【splay】
- bzoj 1503: [NOI2004]郁闷的出纳员 splay
- 【例题】【Splay】NKOJ2504 区间翻转问题
- 【splay】【树状数组】 BZOJ 1503 [NOI2004]郁闷的出纳员
- 【Splay|Treap】poj3580 SuperMemo && bzoj1503 [noi2004]郁闷的出纳员
- BZOJ 1503 郁闷的出纳员 二叉平衡树(Treap,Splay)
- 郁闷的出纳员(splay)
- BZOJ 1503 [NOI2004]郁闷的出纳员 (splay)
- 【splay】BZOJ 1503 郁闷的出纳员
- [BZOJ1503]NOI2004 郁闷的出纳员|splay
- 【codevs1286】【BZOJ1503】郁闷的出纳员,splay练习
- [bzoj]郁闷的出纳员[Splay求第k大]
- BZOJ[NOI2004]郁闷的出纳员 | Splay板子题
- 【NOI2004】郁闷的出纳员 // SPLAY TREE
- BZOJ 1503 郁闷的出纳员(splay)
- BZOJ 1503 [NOI 2004] 郁闷的出纳员 (splay)
- [郁闷的出纳员] ( Splay树 )
- bzoj1503 [NOI2004]郁闷的出纳员 splay
- 大视野 1503 郁闷的出纳员 Splay 初步