zoukankan      html  css  js  c++  java
  • BZOJ1503 [NOI2004]郁闷的出纳员

    Description

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

    Input

    第一行有两个非负整数n和min。n表示下面有多少条命令,min表示工资下界。接下来的n行,每行表示一条命令。命令可以是以下四种之一:

    名称 格式 功能
    I命令 I_k 新建一个工资档案,初始工资为k。如果某员工的
    初始工资低于工资下界,他将立刻离开公司
    A命令 A_k 把每位员工的工资加上k
    S命令 S_k 把每位员工的工资扣除K
    F命令 F_k 查询第K多的工资

    Output

    输出文件的行数为F命令的条数加一。对于每条F命令,你的程序要输出一行,仅包含一个整数,为当前工资第k多的员工所拿的工资数,如果k大于目前员工的数目,则输出-1。输出文件的最后一行包含一个整数,为离开公司的员工的总数。

    Sample Input

    9 10
    I 60
    I 70
    S 50
    F 2
    I 30
    S 15
    A 5
    F 1
    F 2
    

    Sample Output

    10
    20
    -1
    2
    

    HINT

    • I命令的条数不超过100000
    • A命令和S命令的总条数不超过100
    • F命令的条数不超过100000
    • 每次工资调整的调整量不超过1000
    • 新员工的工资不超过100000

    Source

    NOI2004


    题意&思路

    平衡树的裸题,但是很多小的技巧和思路还是让它成为了一道非常经典的题目

    1. del()函数的写法很巧妙,删除从开头开始的连续一段区间
    2. 维护一个变量表示对全局的修改,但是要注意的是插入,删除以及输出的时候都要考虑这个变量的影响
    3. 个人认为平衡树的函数里面,如果涉及到x与t[k].v的比较的话,一般把要操作的量放在前面不容易出错,如插入、查询前驱后继,或者是单点删除。而本题del()函数里在判断时写法是t[k].v<=x,这是因为实际上要操作的量是t[k].v,这里的x相当于只是一个删除的参考值而已。
    4. 注重细节,题目问的是第k大,可以直接写左>根>右的平衡树或者转化为第几小即可。

    Code

    #include<cstdio>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<ctime>
    #define FA(i,s,t) for(int i=(s);i<=(t);i++)
    #define FD(i,s,t) for(int i=(s);i>=(t);i--)
    #define PRI pair<int,int>
    #define LLD long long
    using namespace std;
    
    int getint()
    {
    	int x=0,f=1; char ch=getchar();
    	while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    
    const int INF=(int) 2e9;
    const int MAXN=100000+50;
    
    struct tnode
    {
    	int l,r,s,w,v,rnd;
    }t[MAXN];
    int cnt=0;
    
    #define ls (t[k].l)
    #define rs (t[k].r)
    
    inline void pushup(int k)
    {
    	t[k].s=t[ls].s+t[rs].s+t[k].w;
    }
    inline void rturn(int &k)
    {
    	int tp=ls;ls=t[tp].r;t[tp].r=k;t[tp].s=t[k].s;pushup(k);k=tp;
    }
    inline void lturn(int &k)
    {
    	int tp=rs;rs=t[tp].l;t[tp].l=k;t[tp].s=t[k].s;pushup(k);k=tp;
    }
    
    void ins(int &k,int x)
    {
    	if(!k)
    	{
    		k=++cnt;
    		t[k].v=x;
    		ls=rs=0;
    		t[k].s=t[k].w=1;
    		t[k].rnd=rand();
    		return;
    	}
    	
    	t[k].s++;
    	
    	if(x==t[k].v)
    	{
    		t[k].w++;
    	}
    	else if(x<t[k].v)
    	{
    		ins(ls,x);
    		if(t[ls].rnd<t[k].rnd) rturn(k);
    	}
    	else
    	{
    		ins(rs,x);
    		if(t[rs].rnd<t[k].rnd) lturn(k);
    	}
    }
    int del(int &k,int x) //不能无返回值!因为要修改t[k].s
    {
    	if(!k) return 0;
    	
    	if(t[k].v<x)
    	{
    		int tp=t[ls].s+t[k].w;
    		return tp+del(k=rs,x); //k=rs已经相当于修改了
    	}
    	else
    	{
    		int tp=del(ls,x);
    		t[k].s-=tp;
    		return tp;
    	}
    }
    int kth(int k,int x)
    {
    	int tp=t[ls].s;
    	
    	if(tp<x&&tp+t[k].w>=x)
    	{
    		return t[k].v;
    	}
    	else if(tp>=x)
    	{
    		return kth(ls,x);
    	}
    	return kth(rs,x-tp-t[k].w);
    }
    
    int n,m,root=0,e=0,ans=0;
    
    int main()
    {
    	n=getint();
    	m=getint();
    	
    //	srand(time(0)); //不允许查看系统时间!
    	FA(i,1,n)
    	{
    		char op_c=getchar();
    		while(op_c<'A'||op_c>'Z') op_c=getchar(); 
    		int x=getint();
    		
    		if(op_c=='I')
    		{
    			if(x>=m) ins(root,x-e); //加入也要考虑标记
    		}
    		else if(op_c=='A')
    		{
    			e+=x;
    		}
    		else if(op_c=='S')
    		{
    			e-=x;
    			ans+=del(root,m-e);
    		}
    		else
    		{
    			printf("%d
    ",t[root].s>=x? kth(root,t[root].s-x+1)+e:-1); //同样要考虑标记
    		}
    	}
    	
    	printf("%d
    ",ans);
    	return 0;
    }
    
    
    ----不要温顺地走进那良宵
  • 相关阅读:
    openmp 循环并行化循环嵌套内部无法并行
    c++:strcat潜在的错误不报告
    script php / phpfpm /
    webserver waf / WAF 2.0 / ASERVER/1.2.9
    web test LoadRunner FTP / vsftpd / vsftp / WebUploader 0.1.5 / shangchuan
    my ReadTravel_Singapore / singapore / xinjiapo / lvyou / travel
    OS Security var_log_secure / services / port
    EF操作数据库的步骤和一些简单操作语句
    (大快人心,必须转啊)中国体操男队完美逆转卫冕 日本申诉成功获银牌
    [置顶] 【C/C++学习】之一、指针和引用的区别
  • 原文地址:https://www.cnblogs.com/Hist/p/5037783.html
Copyright © 2011-2022 走看看