P1486 [NOI2004]郁闷的出纳员

P1486 [NOI2004]郁闷的出纳员

题目描述
OIER公司是一家大型专业化软件公司,有着数以万计的员工。作为一名出纳员,我的任务之一便是统计每位员工的工资。这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资。如果他心情好,就可能把每位员工的工资加上一个相同的量。反之,如果心情不好,就可能把他们的工资扣除一个相同的量。我真不知道除了调工资他还做什么其它事情。

工资的频繁调整很让员工反感,尤其是集体扣除工资的时候,一旦某位员工发现自己的工资已经低于了合同规定的工资下界,他就会立刻气愤地离开公司,并且再也不会回来了。每位员工的工资下界都是统一规定的。每当一个人离开公司,我就要从电脑中把他的工资档案删去,同样,每当公司招聘了一位新员工,我就得为他新建一个工资档案。

老板经常到我这边来询问工资情况,他并不问具体某位员工的工资情况,而是问现在工资第k多的员工拿多少工资。每当这时,我就不得不对数万个员工进行一次漫长的排序,然后告诉他答案。

好了,现在你已经对我的工作了解不少了。正如你猜的那样,我想请你编一个工资统计程序。怎么样,不是很困难吧?

如果某个员工的初始工资低于最低工资标准,那么将不计入最后的答案内

输入输出格式
输入格式:
第一行有两个非负整数n和min。n表示下面有多少条命令,min表示工资下界。

接下来的n行,每行表示一条命令。命令可以是以下四种之一:

名称 格式 作用

I命令 I_k 新建一个工资档案,初始工资为k。如果某员工的初始工资低于工资下界,他将立刻离开公司。

A命令 A_k 把每位员工的工资加上k

S命令 S_k 把每位员工的工资扣除k

F命令 F_k 查询第k多的工资

_(下划线)表示一个空格,I命令、A命令、S命令中的k是一个非负整数,F命令中的k是一个正整数。

在初始时,可以认为公司里一个员工也没有。

输出格式:
输出文件的行数为F命令的条数加一。

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

输出文件的最后一行包含一个整数,为离开公司的员工的总数。


降低或提高工资时, 把 \(Treap\) 树中全部节点拿出, 修改后再放回,在时间上不太能够接受(虽然这题数据是可以的), 我们用一个变量 \(lazy\) 维护从刚开始一共变化了多少工资, 所以几个操作转化为如下操作:

1.来新人: 由于有一个基础变化 \(lazy\) 新人享受不到, 一个人只能享受加入公司之后的工资变化, 所以我们向 \(Treap\) 中加入 \(x - lazy\)

2.加工资: 并不会影响员工的走留, 直接累计到 \(lazy\) 即可

3.减工资: 先更新 \(lazy\) 。因为所有员工的最低工资是一样的, 所以要走总是工资最少的。 我们不断查询工资最少的员工, 看是否留下, 若是不留则删除继续看下一个工资多一点的走不走。 一旦发现有一个不走了, 那么后面的都是工资更多的, 也就不会走了。

4.查询第k小: 注意是第k小。直接查询即可, 查出来加上 \(lazy\) 即为答案

Code

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
int RD(){
    int flag = 1, out = 0;char c = getchar();
    while(c < '0' || c > '9'){if(c == '-')flag = -1;c = getchar();}
    while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
    return flag * out;
    }
const int maxn = 1000019, INF = 1e9 + 19;
int ch[maxn][2];
int size[maxn], cnt[maxn];
int val[maxn], dat[maxn];
int root, tot;
int New(int v){
    val[++tot] = v;dat[tot] = rand();
    size[tot] = cnt[tot] = 1;
    return tot;
    }
void pushup(int id){size[id] = size[ch[id][0]] + size[ch[id][1]] + cnt[id];}
void build(){
    root = New(-INF);
    ch[root][1] = New(INF);
    pushup(root);
    }
void Rotate(int &id, int d){
    int temp = ch[id][d ^ 1];
    ch[id][d ^ 1] = ch[temp][d];
    ch[temp][d] = id;
    id = temp;
    pushup(ch[id][d]), pushup(id);
    }
void insert(int &id, int v){
    if(!id){id = New(v);return ;}
    if(val[id] == v){cnt[id]++;pushup(id);return ;}
    int d = v < val[id] ? 0 : 1;
    insert(ch[id][d], v);
    if(dat[ch[id][d]] > dat[id])Rotate(id, d ^ 1);
    pushup(id);
    }
void Remove(int &id, int v){
    if(!id)return ;
    if(val[id] == v){
        if(cnt[id] > 1){cnt[id]--;pushup(id);return ;}
        if(ch[id][0] || ch[id][1]){
            if(!ch[id][1] || dat[ch[id][0]] > dat[ch[id][1]]){
                Rotate(id, 1);
                Remove(ch[id][1], v);
                }
            else Rotate(id, 0), Remove(ch[id][0], v);
            pushup(id);
            }
        else id = 0;
        return ;
        }
    v < val[id] ? Remove(ch[id][0], v) : Remove(ch[id][1], v);
    pushup(id);
    }
int get_val(int id, int rank){
    if(!id)return INF;
    if(size[ch[id][0]] >= rank)return get_val(ch[id][0], rank);
    else if(size[ch[id][0]] + cnt[id] >= rank)return val[id];
    else return get_val(ch[id][1], rank - size[ch[id][0]] - cnt[id]);
    }
int na, minn;
int lazy, c, sum;
int main(){
    na = RD();minn = RD();
    build();
    char cmd;int x;
    for(int i = 1;i <= na;i++){
        cin>>cmd;
        if(cmd == 'I'){
            x = RD();
            if(x >= minn){
                insert(root, x - lazy);
                sum++;
                }
            }
        else if(cmd == 'A'){
            lazy += RD();
            }
        else if(cmd == 'S'){
            x = RD();
            lazy -= x;
            if(sum == 0)continue;
            bool flag = 1;
            while(flag){
                int MIN = get_val(root, 2);
                if(MIN + lazy < minn)Remove(root, MIN), c++, sum--;
                else flag = 0;
                if(sum == 0)break;
                }
            }
        else if(cmd == 'F'){
            x = RD();
            if(sum < x)printf("-1\n");
            else printf("%d\n", get_val(root, size[root] - x) + lazy);
            }
        }
    printf("%d\n", c);
    return 0;
    }

转载于:https://www.cnblogs.com/Tony-Double-Sky/p/9325201.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值