【bzoj1503】【NOI2004】郁闷的出纳员
1503: [NOI2004]郁闷的出纳员
Time Limit: 5 Sec Memory Limit: 64 MB
Submit: 13890 Solved: 5086
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
I 60
I 70
S 50
F 2
I 30
S 15
A 5
F 1
F 2
Sample Output
20
-1
2
HINT
Source
题意:
你需要维护$N$个人的工资,支持以下操作:
- $I$操作:插入一个人,他的初始工资为$x$。
- $A$操作:给所有人的工资加上$x$。
- $S$操作:给所有人的工资减去$x$,如果有人的工资低于了工资下届$M$则把他删除并计入删除总人数$ans$。
- $F$操作:查询现在排名第$x$多的工资是多少,如果人数不足$x$则输出$-1$。
最后输出删除总人数$ans$。
题解:
这道题和平衡树模板的区别只在于$A$操作和$S$操作,也就是说我们需要寻求一个方法能够快速修改平衡树中所有点的点权。
注意到$A,S$操作数量很少,所以暴力修改其实就可以通过本题,但这么做也太没有梦想了吧……
我们发现所有的修改都是对于当前树中所有节点而不是一部分节点,那么是否可以维护一个$dat$表示当前树中所有点共同的增量呢?
虽然树中的点不是同时插入的,但我们如果要把这个增量强行打在新点$x$上,是不是把输入的$x$变成了$x-dat$就行了?
显然是可以的,因为$x-dat$加上现在的增量$dat$还等于$x$,并且不影响它与树中其他节点的大小关系。
那么加操作直接将$dat+x$,减操作先删除所有$< M-dat$的点再修改$dat$就好了。
复杂度$O(N\times log(N))$。
代码:
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> using namespace std; #define MAXN 100005 #define MAXM 500005 #define INF 0x7fffffff #define ll long long struct node{ int v,f,siz,cnt,ch[2]; }tr[MAXN]; int rt,tot,dat,ans; inline int read(){ int x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } inline bool getf(int k){return tr[tr[k].f].ch[1]==k;} inline void update(int k){ tr[k].siz=tr[k].cnt; tr[k].siz+=tr[tr[k].ch[0]].siz; tr[k].siz+=tr[tr[k].ch[1]].siz; return; } inline void rot(int k){ int f1=tr[k].f,f2=tr[f1].f; bool opt=getf(k); tr[f1].ch[opt]=tr[k].ch[opt^1]; tr[tr[k].ch[opt^1]].f=f1; tr[k].ch[opt^1]=f1; tr[f1].f=k;tr[k].f=f2; if(f2) tr[f2].ch[tr[f2].ch[1]==f1]=k; update(f1);update(k); return; } inline void splay(int k){ for(int fa;fa=tr[k].f;rot(k)) if(tr[fa].f) rot(getf(k)==getf(fa)?fa:k); rt=k;return; } inline void ins(int x){ if(!rt){ rt=++tot;tr[tot].v=x; tr[tot].siz=tr[tot].cnt=1; return; } int now=rt,fa=0; while(1){ if(x==tr[now].v){ tr[now].cnt++; update(now);update(fa); splay(now);break; } fa=now;now=tr[now].ch[x>tr[now].v]; if(!now){ tr[++tot].v=x;tr[tot].f=fa; tr[tot].siz=tr[tot].cnt=1; tr[fa].ch[x>tr[fa].v]=tot; update(fa);splay(tot); break; } } return; } inline int qnum(int x){ int now=rt; while(1){ if(tr[tr[now].ch[0]].siz<x && tr[tr[now].ch[0]].siz+tr[now].cnt>=x) return tr[now].v; else if(tr[tr[now].ch[0]].siz>=x) now=tr[now].ch[0]; else x-=tr[tr[now].ch[0]].siz+tr[now].cnt,now=tr[now].ch[1]; } } inline void del(){ ans+=tr[rt].cnt+tr[tr[rt].ch[0]].siz-1; rt=tr[rt].ch[1];tr[rt].f=0; return; } int main(){ //freopen("cashier2.in","r",stdin); //freopen("cashier1.out","w",stdout); int N=read(),M=read(),sum=0; while(N--){ char c;cin>>c;int x=read(); if(c=='I' && x>=M) sum++,ins(x-dat); if(c=='A') dat+=x; if(c=='S') dat-=x,ins(M-dat-1),del(); if(c=='F'){ if(x>sum-ans) printf("-1\n"); else printf("%d\n",qnum(sum-ans-x+1)+dat); } } printf("%d\n",ans); return 0; }