题目描述
有一个公司,有四种操作:
1.拉一个人进入公司,有初始工资
2.每个人的工资加上x
3.每个人的工资减去x
4.查询第k大的工资
当一个人工资低于m时他就会立即离开公司。
要求对于询问输出答案,最后输出离开的人的个数。
题解
查询第k大就用平衡树搞。
主要要解决的就是如何高效的帮助人离开,可以想到找到第一个满足留在公司的人,他前面的人都不满足删掉即可。
2.3操作肯定是懒惰标记搞,因为是每个人平等的(同加同减),所以不会搞乱相对大小,在访问这个点的时候信息是更新好了的。用ret记录第一个满足的人,如果这个人的工资满足,ret就是这个人,然后往左儿子走,不然走右儿子。(可能有点绕,需要理解)
如果ret没记录说明全部都要走(好惨),这时特判搞一搞就好。记录了就旋到根,去掉根的左儿子。
有些地方要注意边界,因为splay可能没元素。
因为工资可能一样,所以要多记录一个num。
在在splay里面走的时候要push_down!!!!插入,删除,查k大
一个人初始工资不满足离开不加入最后答案(坑死我)。

#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
int n,m,root,cnt,ans;
struct Splay{
int fa,s[2],size,tag,val,num;
}tr[maxn];
template<class T>inline void read(T &x){
x=0;int f=0;char ch=getchar();
while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x= f ? -x : x ;
}
void put_tag(int x,int val){
if(!x) return ;
tr[x].val+=val;
tr[x].tag+=val;
}
void push_down(int x){
if(!tr[x].tag) return ;
put_tag(tr[x].s[0],tr[x].tag);
put_tag(tr[x].s[1],tr[x].tag);
tr[x].tag=0;
}
void update(int x){
tr[x].size=tr[tr[x].s[0]].size+tr[tr[x].s[1]].size+tr[x].num;
}
int get(int x){return tr[tr[x].fa].s[1]==x;}
void connect(int x,int y,int d){
tr[x].fa=y;
tr[y].s[d]=x;
}
void rotate(int x){
int f=tr[x].fa,ff=tr[f].fa;
int d1=get(x),d2=get(f);
int cs=tr[x].s[d1^1];
connect(x,ff,d2);
connect(f,x,d1^1);
connect(cs,f,d1);
update(f);
update(x);
}
void splay(int x,int go){
if(go==root) root=x;
go=tr[go].fa;
while(tr[x].fa!=go){
int f=tr[x].fa;
if(tr[f].fa==go) rotate(x);
else if(get(x)==get(f)) {rotate(f);rotate(x);}
else {rotate(x);rotate(x);}
}
}
void debug(int x){
if(!x) return ;
push_down(x);
debug(tr[x].s[0]);
for(int i=1;i<=tr[x].num;i++) printf("%d ",tr[x].val);
debug(tr[x].s[1]);
}
void insert(int val){
if(!root){
root=++cnt;
tr[root]=(Splay){0,{0,0},1,0,val,1};
return ;
}
int now=root;
while(1){
tr[now].size++;
push_down(now);
if(val==tr[now].val){
tr[now].num++;
break;
}
int o=val>tr[now].val;
if(!tr[now].s[o]){
tr[++cnt]=(Splay){now,{0,0},1,0,val,1};
tr[now].s[o]=cnt;
now=cnt;
break;
}
now=tr[now].s[o];
}
splay(now,root);
}
void get_it(){
if(!root) return ;
int now=root,ret=0;
while(1){
if(!now) break;
push_down(now);
if(tr[now].val>=m){
ret=now;
now=tr[now].s[0];
}
else now=tr[now].s[1];
}
if(!ret) {ans+=tr[root].size;root=0;return ;}
splay(ret,root);
if(!tr[root].s[0]) return ;
ans+=tr[tr[root].s[0]].size;
tr[root].s[0]=0;
update(root);
}
int find(int k){
int now=root;
if(!now||tr[now].size<k) return -1;
while(1){
push_down(now);
if(tr[tr[now].s[1]].size>=k) {now=tr[now].s[1];continue;}
k-=tr[tr[now].s[1]].size;
if(tr[now].num>=k) break;
k-=tr[now].num;
now=tr[now].s[0];
}
splay(now,root);
return tr[root].val;
}
int main(){
read(n);read(m);
for(int i=1;i<=n;i++){
char op[2];
scanf("%s",op);
if(op[0]=='I'){
int val;
read(val);
if(val<m) continue;
insert(val);
}
else if(op[0]=='A'){
int val;
read(val);
put_tag(root,val);
}
else if(op[0]=='S'){
int val;
read(val);
put_tag(root,-val);
get_it();
}
else {
int k;
read(k);
printf("%d\n",find(k));
}
//putchar(10);
//debug(root);
//putchar(10);
}
printf("%d",ans);
}
