Description
OIER 公司是一家大型专业化软件公司,有着数以万计的员工。作为一名出纳员,我的任务之一便是统计每位员工的工资。这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资。如果他心情好,就可能把每位员工的工资加上一个相同的量。反之,如果心情不好,就可能把他们的工资扣除一个相同的量。我真不知道除了调工资他还做什么其它事情。
工资的频繁调整很让员工反感,尤其是集体扣除工资的时候,一旦某位员工发现自己的工资已经低于了合同规定的工资下界,他就会立刻气愤地离开公司,并且再也不会回来了。每位员工的工资下界都是统一规定的。每当一个人离开公司,我就要从电脑中把他的工资档案删去,同样,每当公司招聘了一位新员工,我就得为他新建一个工资档案。
老板经常到我这边来询问工资情况,他并不问具体某位员工的工资情况,而是问现在工资第 k 多的员工拿多少工资。每当这时,我就不得不对数万个员工进行一次漫长的排序,然后告诉他答案。
好了,现在你已经对我的工作了解不少了。正如你猜的那样,我想请你编一个工资统计程序。怎么样,不是很困难吧?Input
第一行有两个非负整数 n 和 min 。n 表示下面有多少条命令,min 表示工资下界。
接下来的 n 行,每行表示一条命令。命令可以是以下四种之一:
“下划线( _ )”表示一个空格,I 命令、A 命令、S 命令中的 k 是一个非负整数,F 命令中的 k 是一个正整数。
在初始时,可以认为公司里一个员工也没有。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 2Sample Output
10
20
-1
2Hint
【数据范围】
I 命令的条数不超过 100000
A 命令和 S 命令的总条数不超过 100
F 命令的条数不超过 100000
每次工资调整的调整量不超过 1000
新员工的工资不超过 100000题解 : Splay
对于每个Splay上的点,维护size和val.
对于几种操作的方法:
插入
先判断该点能否被插入。如果能则计数器加一。
插入时可以将m(增加减少量)先更新Splay,每个点-m(tag标记)。或者直接在加入值上+m;
最后输出离开的员工就用总员工减剩余员工。
增加、减少
外部设置计数器m,在m上加减即可。及时删除。
删除操作:
对于一个节点,可能的情况有两种:
1.当前值小于最小值。
该节点及其左子树都会被删除。将该节点右子树置为该节点父亲的儿子,更新父亲。(若该节点为根节点则将右子树置为根节点)。递归删除右子树。
2.当前值大等于最小值。
直接递归删除左子树即可。
- Code
#include<bits/stdc++.h>
using namespace std;
const int Maxn=1e5+50;
inline int read()
{
char ch=getchar();int i=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}
return i*f;
}
struct node
{
node *fa,*lc,*rc;
int val,sze,tag;
node():fa(NULL),lc(NULL),rc(NULL){}
void upt()
{
sze=(lc?lc->sze:0)+(rc?rc->sze:0)+1;
}
}POOL[Maxn],*pool=POOL,*rt;
int n,m,M,cnt;
char ch[2];
inline node* newnode(int val)
{
++pool;
pool->sze=1;
pool->val=val;
return pool;
}
inline bool which(node *now)
{
return now->fa->lc==now;
}
inline void Rotate(node *x)
{
node* y=x->fa,*z=y->fa;
x->fa=z,y->fa=x;
if(y->lc==x)
{
if(z)(z->lc==y?z->lc:z->rc)=x;
if(x->rc)x->rc->fa=y,y->lc=x->rc;
else y->lc=NULL;
x->rc=y;
y->upt();x->upt();
}
else
{
if(z)(z->lc==y?z->lc:z->rc)=x;
if(x->lc)x->lc->fa=y,y->rc=x->lc;
else y->rc=NULL;
x->lc=y;
y->upt();x->upt();
}
}
inline void Splay(node* x)
{
while(x->fa)
{
node *y=x->fa;
if(y->fa)
{
if(which(x)^which(y))Rotate(x);
else Rotate(y);
}
Rotate(x);
}
rt=x;
}
inline void pushdown(node *now,int val)
{
now->val-=val;
now->tag=0;
if(now->lc)now->lc->tag+=val;
if(now->rc)now->rc->tag+=val;
}
inline node* Insert(node* f,node*& now,int val)
{
if(!now)
{
now=newnode(val);
now->fa=f;
return now;
}
if(now->tag)pushdown(now,now->tag);
if(val<=now->val)
{
node* tmp=Insert(now,now->lc,val);
now->upt();
return tmp;
}
else
{
node* tmp=Insert(now,now->rc,val);
now->upt();
return tmp;
}
}
inline void Delete(node *now,int val)
{
if(now->tag)pushdown(now,now->tag);
if(now->val<val)
{
if(now==rt)rt=now->rc;
if(now->rc)
{
now->rc->fa=now->fa;
if(now->fa)(now->fa->lc==now?now->fa->lc:now->fa->rc)=now->rc;
Delete(now->rc,val);
now->rc->upt();
if(now->fa)now->fa->upt();
}
else if(now->fa)
{
(now->fa->lc==now?now->fa->lc:now->fa->rc)=NULL;
now->fa->upt();
}
}
else
{
if(now->lc)
{
Delete(now->lc,val);
}
now->upt();
}
}
inline int Find(node* now,int k)
{
if(now->tag)pushdown(now,now->tag);
if((now->lc?now->lc->sze:0)==(k-1))return now->val;
else if((now->lc?now->lc->sze:0)>=k)return Find(now->lc,k);
else return Find(now->rc,(k-(now->lc?now->lc->sze:0)-1));
}
int main()
{
rt=NULL;
n=read(),M=read();
for(int i=1;i<=n;i++)
{
scanf("%s",ch+1);
switch(ch[1])
{
case 'I':
{
if(rt)rt->tag+=m;
m=0;
int val=read();
if(val>=M)
{
cnt++;
if(!rt)rt=newnode(val);
else Splay(Insert(rt->fa,rt,val));
}
break;
}
case 'S':
{
int x=read();
m+=x;
Delete(rt,m+M);
break;
}
case 'A':
{
int x=read();
m-=x;
break;
}
case 'F':
{
int k=read();
if(!rt)
{
puts("-1");
break;
}
k=rt->sze-k+1;
if(k>rt->sze||k<=0)puts("-1");
else cout<<Find(rt,k)-m<<endl;
break;
}
}
}
cout<<cnt-(rt?rt->sze:0)<<endl;
}