有一个公司,有四种操作:
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); }
原文:https://www.cnblogs.com/sto324/p/11380218.html