[NOI 2004]郁闷的出纳员

来源:互联网 发布:手机取色软件 编辑:程序博客网 时间:2024/04/29 11:40

这是一道练手的水题啦!写网络流怕把splay忘了,于是来练习一下splay。这是一道很经典的splay入门题,用size域查询排名,维护的仍然是有序表,只是由于涉及到删除插入的操作,包括询问排名,所以线段树不是很好实现(但事实上是可以的)。
尽管是道很基础的题,但是还是有很多地方值得注意:
1、由于员工工资可能是一样的,所以如果让重复的元素出现在树中,则会使删除操作变得异常麻烦。于是我们应该添加一个num域表示当前元素在树中出现的个数。那么有两个操作将被修改:
(1). 在进行update更新时,函数应变成

        this->size=l->size+r->size+this->num;

(2). 查找第k大的元素也应该修改,具体看代码

2、在进行删除操作时,千万不能删多了,这个有一些写法上的技巧。

3、splay的关键地方必须及时更新,否则可能会出现奇怪的错误。

4、这个题目的大坑点,如果某员工开始时工资低于最低工资标准,那么他不用算在离开的人数内(出题人语文没学好O__O"…)。

#include <cstdio>#define __add(x,w) lazy[x]+=w,a[x]+=w#define update(x) if((x)) s[x]=s[l[x]]+s[r[x]]+num[x]#define MaxN 100010using namespace std;int a[MaxN],l[MaxN],r[MaxN],num[MaxN],s[MaxN],lazy[MaxN];int n,low,t,tot,ans;inline void push(const int &x){if(!x) return;__add(l[x],lazy[x]);__add(r[x],lazy[x]);lazy[x]=0;}inline void zig(int &x){int lc=l[x];l[x]=r[lc];r[lc]=x;update(x);x=lc;}inline void zag(int &x){int rc=r[x];r[x]=l[rc];l[rc]=x;update(x);x=rc;}inline void splay(int &t,int x){if(!t) return;int p,pl=0,pr=0,last;for(;;){push(t);push(l[t]);push(r[t]);if(x==a[t]) break;if(x<a[t]&&!l[t]) break;if(x>a[t]&&!r[t]) break;if(x<a[t]){if(x<a[l[t]]&&l[l[t]]) zig(t);p=l[t],l[t]=pr,pr=t,t=p;}else{if(x>a[r[t]]&&r[r[t]]) zag(t);p=r[t],r[t]=pl,pl=t,t=p;}}last=l[t];while(pl){p=r[pl],r[pl]=last;update(pl);last=pl,pl=p;}l[t]=last;last=r[t];while(pr){p=l[pr],l[pr]=last;update(pr);last=pr,pr=p;}r[t]=last;update(t);}inline void insert(const int &x){if(x<low) return;splay(t,x);if(!t) a[++tot]=x,t=tot;if(x==a[t]){num[t]++;update(t);}else{a[++tot]=x;num[tot]++;if(x<a[t])l[tot]=l[t],l[t]=tot;elser[tot]=r[t],r[t]=tot;update(tot);update(t);}}inline void cheak(){splay(t,low);if(a[t]<low) splay(r[t],a[t]),zag(t);ans+=s[l[t]];l[t]=0;update(t);}inline int ask(int &x){if(x>s[t]) return -1;int temp=t,cmp;for(;;){push(temp);push(l[temp]);push(r[temp]);cmp=s[r[temp]]+num[temp];if(x<=cmp&&x>s[r[temp]])return a[temp];else if(x<=s[r[temp]])temp=r[temp];elsex-=cmp,temp=l[temp];}}int main(){//freopen("in","r",stdin);//freopen("out","w",stdout);char s[2];int x;scanf("%d%d",&n,&low);while(n--){scanf("%s%d",s,&x);if(s[0]=='I')insert(x);else if(s[0]=='A')__add(t,x);else if(s[0]=='S')__add(t,-x),cheak();else printf("%d\n",ask(x));}printf("%d",ans);return 0;} 

0 0
原创粉丝点击