题意
OIER公司是一家大型专业化软件公司,有着数以万计的员工。作为一名出纳员,我的任务之一便是统计每位员工的
工资。这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资。如果他心情好
,就可能把每位员工的工资加上一个相同的量。反之,如果心情不好,就可能把他们的工资扣除一个相同的量。我
真不知道除了调工资他还做什么其它事情。工资的频繁调整很让员工反感,尤其是集体扣除工资的时候,一旦某位
员工发现自己的工资已经低于了合同规定的工资下界,他就会立刻气愤地离开公司,并且再也不会回来了。每位员
工的工资下界都是统一规定的。每当一个人离开公司,我就要从电脑中把他的工资档案删去,同样,每当公司招聘
了一位新员工,我就得为他新建一个工资档案。老板经常到我这边来询问工资情况,他并不问具体某位员工的工资
情况,而是问现在工资第k多的员工拿多少工资。每当这时,我就不得不对数万个员工进行一次漫长的排序,然后
告诉他答案。好了,现在你已经对我的工作了解不少了。正如你猜的那样,我想请你编一个工资统计程序。怎么样
,不是很困难吧?
input
第一行有两个非负整数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是一个正整数。
在初始时,可以认为公司里一个员工也没有。
I命令的条数不超过100000
A命令和S命令的总条数不超过100
F命令的条数不超过100000
每次工资调整的调整量不超过1000
新员工的工资不超过100000
output
输出行数为F命令的条数加一。
对于每条F命令,你的程序要输出一行,仅包含一个整数,为当前工资第k多的员工所拿的工资数,
如果k大于目前员工的数目,则输出-1。
输出文件的最后一行包含一个整数,为离开公司的员工的总数。
思路
准备用无旋treap练练手…
基本只要满足插入操作,和查询第K大就行。一个难点在于,每次修改权值对整体操作,同时要动态的查看当前有多少比 low小,然后整个删掉。可以按时间顺序维护一个sum,表示当前每个人的增量,每次sum变动之后 change 就是查找比 low-sum 小的个数。如果要新插入一个数字,除了特判当前和low的关系决定插不插入以外,之前的sum是不对其进行影响的,但是每次查完第 k 的要加上增量,因此在加入treap的时候先减去 sum,这样是符合要求的,不必担心 减完之后小于low怎么办,因为 low的基准也是 减去增量 sum的,所以相当于等式两边同时减掉sum。
然后代码方面我还是写的 siz_split ,这样会多比 val_split多一个getrank的时间,较之前对split的新理解就是,通过merge的左右关系,保证了权值/序列的有序性,val_split可以用siz_split结合getrank代替。
代码
贴一下FHQ_treap 板子。
#include<bits/stdc++.h>
using namespace std;
#define maxn 300005
#define maxm 1006
#define ll long long int
#define INF 0x3f3f3f3f
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
#define mem(a) memset(a,0,sizeof(a))
#define sqr(x) (x*x)
#define inf (ll)2e18+1
#define PI acos(-1)
#define mod 10007
#define auto(i,x) for(int i=head[x];i;i=ed[i].nxt)
ll read(){
ll x=0,f=1ll;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
int n,low;
int val[maxn],rnd[maxn],siz[maxn],ls[maxn],rs[maxn],tot,rt,sum,lef;
void pushup(int x){siz[x]=siz[ls[x]]+siz[rs[x]]+1; }
void split(int now,int k,int &x,int &y){
if(now==0){x=y=0;return ;}
if(k<=siz[ls[now]]){
y=now;
split(ls[now],k,x,ls[now]);
}
else {
x=now;
split(rs[now],k-siz[ls[now]]-1,rs[now],y);
}
pushup(now);
}
void Merge(int &now,int x,int y){
if(!x||!y){now=x+y;return ;}
if(rnd[x]<rnd[y]){
now=x;
Merge(rs[now],rs[now],y);
}
else{
now=y;
Merge(ls[now],x,ls[now]);
}
pushup(now);
}
int getrank(int va){
int res=0,mi=INF,now=rt;
while(now){
if(va<=val[now]){
if(va==val[now])mi=min(mi,res+siz[ls[now]]);
now=ls[now];
}
else{
res+=siz[ls[now]]+1;
now=rs[now];
}
}
return mi==INF?res:mi;
}
void insert(int va){
if(va<low)return ;
va-=sum;///
int pos=getrank(va);
int x=0,y=0,z=0;
split(rt,pos,x,y);
z=++tot;
rnd[z]=rand();val[z]=va;siz[z]=1;ls[z]=rs[z]=0;
Merge(rt,x,z);
Merge(rt,rt,y);
}
void change(int va){
//if(va>=0)return ;
///这里不能因为sum>=0就不修改 因为可能有刚刚插进来的 然后sum--了 于是low-sum 的标准提高了
///例如 sum=10 low=10
///I 10
///S 1
int pos=getrank(low-va);
int x=0,y=0,z=0;
split(rt,pos,x,z);
rt=z;lef+=siz[x];
}
int getnum(int pos){
if(pos>siz[rt])return -1;
pos=siz[rt]-pos+1;
int x=0,y=0,z=0;
split(rt,pos,x,z);
split(x,pos-1,x,y);
int res=val[y];
Merge(rt,x,y);
Merge(rt,rt,z);
return res;
}
void dfs(int x){
if(val[x]==0){printf("*\n");return ; }
printf("val = %d siz = %d\n",val[x],siz[x]);
dfs(ls[x]);
dfs(rs[x]);
printf("val = %d siz = %d\n",val[x],siz[x]);
}
int main()
{
srand(234213);
n=read();low=read();
char s[5];
int x;
inc(i,1,n){
scanf("%s",s);
if(s[0]=='I'){
x=read();
insert(x);
}
else if(s[0]=='A'){
x=read();
sum+=x;
change(sum);
}
else if(s[0]=='S'){
x=read();
sum-=x;
change(sum);
}
else{
x=read();
if(x>siz[rt])printf("-1\n");
else printf("%d\n",getnum(x)+sum);
}
//printf("sum = %d\n",sum);
//dfs(rt);
}
printf("%d\n",lef);
return 0;
}