• bzoj 1503: [NOI2004]郁闷的出纳员


    Description

    OIER公司是一家大型专业化软件公司,有着数以万计的员工。作为一名出纳员,我的任务之一便是统计每位员工的工资。这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资。如果他心情好,就可能把每位员工的工资加上一个相同的量。反之,如果心情不好,就可能把他们的工资扣除一个相同的量。我真不知道除了调工资他还做什么其它事情。
    工资的频繁调整很让员工反感,尤其是集体扣除工资的时候,一旦某位员工发现自己的工资已经低于了合同规定的工资下界,他就会立刻气愤地离开公司,并且再也不会回来了。每位员工的工资下界都是统一规定的。每当一个人离开公司,我就要从电脑中把他的工资档案删去,同样,每当公司招聘了一位新员工,我就得为他新建一个工资档案。
    老板经常到我这边来询问工资情况,他并不问具体某位员工的工资情况,而是问现在工资第k多的员工拿多少工资。每当这时,我就不得不对数万个员工进行一次漫长的排序,然后告诉他答案。
    好了,现在你已经对我的工作了解不少了。正如你猜的那样,我想请你编一个工资统计程序。怎么样,不是很困难吧?
    如果某个员工的初始工资低于最低工资标准,那么将不计入最后的答案内

    solution

    正解:平衡树
    我们维护一个全局变量(f),为之前扣除量之和,每一次扣除我们把下界加上k,并把小于下界的都删除,(split)一下前几个即可,每次插入的时候,初始工资要加上(f),并且离开的人数总和不算一开始就离开的

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #define RG register
    #define il inline
    #define iter iterator
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    using namespace std;
    const int N=100005;
    typedef long long ll;
    int Q,lim,ch[N][2],key[N],sz[N],v[N],rt,cnt=0,lazy[N],f=0;
    inline void upd(int x){if(x)sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;}
    inline void down(int x){
    	if(!x || !lazy[x])return ;
    	int ls=ch[x][0],rs=ch[x][1],k=lazy[x];
    	if(ls)v[ls]+=k,lazy[ls]+=k;
    	if(rs)v[rs]+=k,lazy[rs]+=k;
    	lazy[x]=0;
    }
    inline void split(int x,int k,int &a,int &b){
    	if(!k){a=0;b=x;return ;}
    	down(x);
    	int l=ch[x][0],r=ch[x][1];
    	if(sz[l]==k)ch[x][0]=0,a=l,b=x;
    	else if(sz[l]+1==k)ch[x][1]=0,a=x,b=r;
    	else if(sz[l]>k)split(l,k,a,ch[x][0]),b=x;
    	else split(r,k-sz[l]-1,ch[x][1],b),a=x;
    	upd(x);
    }
    inline int merge(int x,int y){
    	if(!x || !y)return x+y;
    	down(x);down(y);
    	if(key[x]>key[y]){
    		ch[x][1]=merge(ch[x][1],y);
    		upd(x);
    		return x;
    	}
    	else{
    		ch[y][0]=merge(x,ch[y][0]);
    		upd(y);
    		return y;
    	}
    }
    inline int rank(int k){
    	int ret=1,x=rt;
    	while(x){
    		down(x);
    		if(k<=v[x])x=ch[x][0];
    		else ret+=sz[ch[x][0]]+1,x=ch[x][1];
    	}
    	return ret;
    }
    inline void ins(int x){
    	if(x<lim)return ;
    	int l,r;
    	v[++cnt]=x;key[cnt]=rand();sz[cnt]=1;
    	split(rt,rank(x)-1,l,r);
    	rt=merge(merge(l,cnt),r);
    }
    inline void Delet(int k){int l;split(rt,k,l,rt);}
    inline int kth(int k){
    	int x=rt,sum;
    	while(x){
    		down(x);
    		sum=sz[ch[x][1]];
    		if(sum==k-1)return v[x];
    		if(sum>=k)x=ch[x][1];
    		else k-=sum+1,x=ch[x][0];
    	}return -1;
    }
    void work()
    {
    	int x,y,ans=0;char S[3];
    	scanf("%d%d",&Q,&lim);
    	while(Q--){
    		scanf("%s%d",S,&x);
    		if(S[0]=='I')ins(x+f);
    		else if(S[0]=='A')v[rt]+=x,lazy[rt]+=x;
    		else if(S[0]=='S'){
    			f+=x,lim+=x;
    			y=rank(lim)-1;
    			if(y>=1)Delet(y),ans+=y;
    		}
    		else y=kth(x),printf("%d
    ",y==-1?-1:y-f);
    	}
    	printf("%d
    ",ans);
    }
         
    int main()
    {
    	freopen("pp.in","r",stdin);
    	freopen("pp.out","w",stdout);
    	work();
    	return 0;
    }
    
    
  • 相关阅读:
    Linux架构浅谈
    SP3精密星历简介
    sprintf的用法
    插值 回归 拟合 逼近的区别
    Linux grep命令
    看我如何下载韩寒博客文章笔记
    多线程下载
    网络爬虫python教程
    爬虫——博客实例
    Android Studio安装
  • 原文地址:https://www.cnblogs.com/Yuzao/p/8097332.html
Copyright © 2020-2023  润新知