首页 > 其他 > 详细

[NOI2004]郁闷的出纳员

时间:2020-01-13 20:04:31      阅读:72      评论:0      收藏:0      [点我收藏+]

题目描述

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

输入格式

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

  • \(\texttt{I k}\) 新建一个工资档案,初始工资为 \(k\)。如果某员工的初始工资低于工资下界,他将立刻离开公司。
  • \(\texttt{A k}\) 把每位员工的工资加上 \(k\)
  • \(\texttt{S k}\) 把每位员工的工资扣除 \(k\)
  • \(\texttt{F k}\) 查询第 \(k\) 多的工资。

    输出格式

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

    输入输出样例

    输入

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

    输出

    10
    20
    -1
    2

解析

\(splay\) 够爽,调了一天代码!
就用 \(splay\),模板还不切?
具体 \(splay\) 的操作,预见我的学习笔记
谨慎学 \(splay\) ,温馨提示,
上网学 \(splay\) ,风险特别多。
一份好博客,省你一天劳!
因为网上“极好”的博客,使我对着一份代码折腾了自己一天

好,因为是模板题,所以对每个操作说明一下就好了
对于 \(\texttt{I k}\) ,把它当成 \(Insert\) 操作,把 \(\geq min\) 的工资插入即可
对于 \(\texttt{A k}\)\(\texttt{S k}\),暴力加或减即可。
对于 \(\texttt{F k}\),那就查询第 \(k\) 大好了

然而,减数后,有些人将被淘汰
所以我想了一个 \(leave\) 操作
\(\min-1\) 的后继旋转到根,左子树都比跟小,因为根 \(\geq min\) 所以左子树都将被淘汰,删去即可
但要查后继,万一没有后继岂不就 \(gg\) 了吗?
所以插入一个极大值

珍惜生命,注意细节!

代码

#include<cstdio>
using namespace std;

const int N = 1e5 , INF = 1e9;
int n , min , k , root , tot , sum;
char opt;

struct tree{
    int ch[2] , size , val , cnt , fa;
}t[N + 5];

inline int read()
{
    register char ch = getchar();
    register int res = 0;
    while (ch < '0' || ch > '9') ch = getchar();
    while (ch >= '0' && ch <= '9') res = res * 10 + ch - '0' , ch = getchar();
    return res;
}

inline void update(int x)
{
    t[x].size = t[t[x].ch[0]].size + t[t[x].ch[1]].size + t[x].cnt;
}

inline void rotate(int x)
{
    register int y = t[x].fa , z = t[y].fa , k = t[y].ch[1] == x;
    t[z].ch[t[z].ch[1] == y] = x , t[x].fa = z;
    t[y].ch[k] = t[x].ch[k ^ 1] , t[t[x].ch[k ^ 1]].fa = y;
    t[x].ch[k ^ 1] = y , t[y].fa = x;
    update(y) , update(x);
}
inline void splay(int x , int goal)
{
    while (t[x].fa != goal)
    {
        int y = t[x].fa , z = t[y].fa;
        if (z != goal) (t[z].ch[0] == y) ^ (t[y].ch[0] == x) ? rotate(x) : rotate(y);
        rotate(x);
    }
    if (goal == 0) root = x;
}

inline void insert(int x)
{
    register int u = root , fa = 0;
    while (u && t[u].val != x) fa = u , u = t[u].ch[x > t[u].val];
    if (u) t[u].cnt++;
    else 
    {
        u = ++tot;
        if (fa) t[fa].ch[x > t[fa].val] = u;
        t[u].ch[1] = t[u].ch[0] = 0 , t[u].size = t[u].cnt = 1 , t[u].fa = fa , t[u].val = x;
    }
    splay(u , 0);
}

inline int kth(int x)
{
    register int u = root;
    if (t[u].size < x) return -1;
    while (1)
    {
        register int y = t[u].ch[1];
        if (x > t[y].size + t[u].cnt) x -= t[y].size + t[u].cnt , u = t[u].ch[0];
        else 
        {
            if (t[y].size >= x) u = y;
            else return t[u].val;
        }
    }
}

inline void find(int x)
{
    register int u = root;
    if (!u) return;
    while (t[u].ch[x > t[u].val] && x != t[u].val) u = t[u].ch[x > t[u].val];
    splay(u , 0);
}

inline int Next(int x , int f)
{
    find(x);
    register int u = root;
    if ((t[u].val > x && f) || (t[u].val < x && !f)) return u;
    u = t[u].ch[f];
    while (t[u].ch[f ^ 1] != 0) u = t[u].ch[f ^ 1];
    return u;
}

inline int leave()
{
    register int u = Next(min - 1 , 1);
    splay(u , 0) , sum += t[t[u].ch[0]].size , t[u].ch[0] = 0 , update(u);
}

int main()
{
    n = read() , min = read();
    insert(INF);
    for(register int i = 1; i <= n; i++)
    {
        opt = getchar();
        while (opt != 'I' && opt != 'A' && opt != 'S' && opt != 'F') opt = getchar(); 
        k = read();
        if (opt == 'I' && k >= min) insert(k);
        else if (opt == 'A')
            for(register int j = 1; j <= tot; j++) t[j].val += k;
        else if (opt == 'S')
        {
            for(register int j = 1; j <= tot; j++) t[j].val -= k;
            leave();
        }
        else if (opt == 'F') printf("%d\n" ,  kth(k + 1));
    }
    printf("%d" , sum);
} 

[NOI2004]郁闷的出纳员

原文:https://www.cnblogs.com/leiyuanze/p/12188748.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!