• bzoj1503 [NOI2004]郁闷的出纳员


    1503: [NOI2004]郁闷的出纳员

    Time Limit: 5 Sec  Memory Limit: 64 MB
    Submit: 12785  Solved: 4577
    [Submit][Status][Discuss]

    Description

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

    Input

    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

    分析:郁闷的程序员......这种样子的题一看就是要用数据结构来实现.考虑用splay来实现.对于I操作,直接插入就可以了.A,S两种操作是区间修改.因为是对整体修改,所以可以用一个变量sum表示当前的工资下界与最开始的工资下界相差多少.这样如果要插入一个数x,插入x-sum就可以了,最后+sum就能够还原了.每次S操作后要删除低于工资下界的人,维护一个特征点min - sum,为了方便处理,将这个点插入到splay中,转到根部,那么它的左子树连同它自己都要被删掉.保留右子树.

              需要注意的是可能会有多个数相同,那么删除就不能直接删掉整个点了,而要判断当前点的个数是否 > 1.第k大是从大到小第k个,而不是从小到大.还要及时更新size数组.一旦一个点的cnt或者size变了,就要更新它的父节点,连同自己.

              以前用的模板在这道题上有问题,换了一个更好的模板:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 200010;
    
    int n,minn,root,tot,sizee[maxn],ans,sum;
    bool flag = false;
    
    struct node
    {
        int left,right,fa,v,cnt;
    }e[maxn];
    
    void update(int x)
    {
        sizee[x] = e[x].cnt;
        if (e[x].left != 0)
            sizee[x] += sizee[e[x].left];
        if (e[x].right != 0)
            sizee[x] += sizee[e[x].right];
    }
    
    int getsize(int x)
    {
        if (x == 0)
            return 0;
        return sizee[x];
    }
    
    void turnr(int x)
    {
        int y = e[x].fa;
        int z = e[y].fa;
        e[y].left = e[x].right;
        if (e[x].right != 0)
            e[e[x].right].fa = y;
        e[x].fa = z;
        if (z != 0)
        {
            if (e[z].left == y)
                e[z].left = x;
            else
                e[z].right = x;
        }
        e[x].right = y;
        e[y].fa = x;
        update(x);
        update(y);
    }
    
    void turnl(int x)
    {
        int y = e[x].fa;
        int z = e[y].fa;
        e[y].right = e[x].left;
        if (e[x].left != 0)
            e[e[x].left].fa = y;
        e[x].fa = z;
        if (z != 0)
        {
            if (e[z].left == y)
                e[z].left = x;
            else
                e[z].right = x;
        }
        e[x].left = y;
        e[y].fa = x;
        update(x);
        update(y);
    }
    
    void splay(int x)
    {
        while (e[x].fa != 0)
        {
            int y = e[x].fa;
            int z = e[y].fa;
            if (z == 0)
            {
                if (x == e[y].left)
                    turnr(x);
                else
                    turnl(x);
            }
            else
            {
                if (e[z].left == y && e[y].left == x)
                {
                    turnr(y);
                    turnr(x);
                }
                else
                {
                    if (e[z].right == y && e[y].right == x)
                    {
                        turnl(y);
                        turnl(x);
                    }
                    else
                    {
                        if (e[z].left == y && e[y].right == x)
                        {
                            turnl(x);
                            turnr(x);
                        }
                        else
                        {
                                turnr(x);
                                turnl(x);
                        }
                    }
                }
            }
        }
        root = x;
    }
    
    void insert(int x)
    {
        if (!root)
        {
            ++tot;
            e[tot].left = e[tot].right = e[tot].fa = 0;
            e[tot].v = x;
            e[tot].cnt = sizee[tot] = 1;
            root = tot;
            return;
        }
        int now = root,fa = 0;
        while (1)
        {
            if(e[now].v == x)
            {
                e[now].cnt++;
                update(now);
                update(fa);
                splay(now);
                break;
            }
            fa = now;
            if (e[now].v < x)
                now = e[now].right;
            else
                now = e[now].left;
            if (!now)
            {
                ++tot;
                e[tot].left = e[tot].right = 0;
                e[tot].fa = fa;
                e[tot].v = x;
                e[tot].cnt = sizee[tot] = 1;
                if (e[fa].v < x)
                    e[fa].right = tot;
                else
                    e[fa].left = tot;
                update(fa);
                splay(tot);
                break;
            }
        }
    }
    
    void clear(int x)
    {
        e[x].fa = e[x].left = e[x].right = e[x].v = e[x].cnt = sizee[x] = 0;
    }
    
    void del()
    {
        ans += sizee[e[root].left];
        e[root].left = 0;
        if (e[root].cnt > 1)
        {
            e[root].cnt--;
            update(root);
            return;
        }
        if (!e[root].right)
        {
            root = 0;
            return;
        }
        root = e[root].right;
        e[root].fa = 0;
    }
    
    int query(int x)
    {
        int p = root;
        while (p != 0)
        {
            if (e[p].right != 0 && x <= sizee[e[p].right])
                p = e[p].right;
            else
            {
                int temp = getsize(e[p].right) + e[p].cnt;
                if (x <= temp)
                return e[p].v;
                x -= temp;
                p = e[p].left;
            }
        }
        return e[p].v;
    }
    
    
    int main()
    {
        scanf("%d%d",&n,&minn);
        for (int i = 1; i <= n; i++)
        {
            char op[2];
            int k;
            scanf("%s",op);
            scanf("%d",&k);
            if (op[0] == 'I')
            {
                if (k < minn)
                    continue;
                insert(k - sum);
            }
            if (op[0] == 'A')
                sum += k;
            if (op[0] == 'S')
            {
                sum -= k;
                insert(minn - sum);
                del();
            }
            if (op[0] == 'F')
            {
                update(root);
                if (sizee[root] < k)
                    puts("-1");
                else
                    printf("%d
    ",query(k) + sum);
            }
        }
        printf("%d
    ",ans);
    
        return 0;
    }
  • 相关阅读:
    docker 如何启动空容器
    dotnet5.0 aspnetcore runtime docker镜像
    abp asp.net core 手动获取容器中的服务
    我把代码写在别人的分支了?别慌,有办法解决
    var重复声明为什么后续声明会被忽略
    flex布局不常用到的属性整理
    微信openID和unionID的区别
    js稀疏数组、密集数组、数组空位、手写数组map方法
    vscode格式化代码换行?试试这个配置
    封装一个公共组件并上传到npm仓库
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8261757.html
Copyright © 2020-2023  润新知