zoukankan      html  css  js  c++  java
  • 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。

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

    输入输出样例

    输入样例#1: 复制
    9 10
    I 60
    I 70
    S 50
    F 2
    I 30
    S 15
    A 5
    F 1
    F 2
    
    输出样例#1: 复制
    10
    20
    -1
    2
    

    说明

    I命令的条数不超过100000

    A命令和S命令的总条数不超过100

    F命令的条数不超过100000

    每次工资调整的调整量不超过1000

    新员工的工资不超过100000

    //让这道板子题难死我。。。调了一天了 
    //换了有四五种思路,最后发现我并没有想错,就是这么写 
    //犯了一个很sb的错误,原因是想的方法太多了,没改过来,保持了上一种写法的样子 
    //但是我感觉貌似并没影响啊。。。但是它就是WA了 
    //一个遗漏的小细节,浪费了一下午的时间 
    //但是   因为绞尽脑汁地A掉这道题,所以我又学会了一些骚操作
    // 但是依然感觉很亏啊    好好的时间,就这么流走了
    
    //    思路:
    //正常的treap操作,删除的时候暴力枚举删除(/滑稽),不用担心TLE
    //本来想加个并查集维护一下删除操作,但是做出这道题来之后已经完全没心情了
    //如果一个人跳槽了,就给他打个标记,下次涨工资或者减工资的时候就continue掉
    //别的就和板子一个样了
    
    //我犯的几个zz错误:
    //1、注意题目中说一开始工资不够离开的不加入答案 (我并没犯这个错误)
    //2、询问的是工资第k大的人的工资是多少,不是问第k大的工资是多少!!!——>这个很重点,就是因为这个,我换了一种思路写的代码
    //3、如果你写的是左儿子比右儿子大的treap,那么查找的时候找的是(在职人数-x+1),因为你的查询查询的是第k小
    //        如果是右儿子比左儿子小的,直接查找x就行了。 
    //5、删除的时候要让root->size-=删除的那个工资的人数,不是 --root->size 
    //4、可能会有职工的工资是一样的,所以要记录相同工资的人数。 ->第2条和第5条的原因
    
    //忠告:慎用指针!  虽然功能强大,但是太难调试,而且一些操作并不能像数组一样那么灵活的去执行。
    //        本人不会用指针    如果是指针大佬。就当我没说。 
    
    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int N=1e5+5;
    const int INF=599518803;
    
    int n,minn;
    int opt,x;
    int tim,sum_peo,leave_peo;
    int add[N],sub[N];
    struct Node
    {
        Node *son[2];    //左右儿子,son[0]是左儿子,son[1]是右儿子 
        int key;    //权值 
        int heap_key;    //维护堆的权值 
        int key_cnt;    //节点的重量 
        int size;    //子树的节点个数 
        int tim;    //进公司的时间 
        bool flag;    //是否跳槽 
    }node[N];
    
    typedef Node* Tree;
    Tree now_node,root,null;
    
    int read()
    {
        char c=getchar();int num=0,f=1;
        for(;!isdigit(c);c=getchar())
            switch(c)
            {
                case 'I':return 1;
                case 'A':return 2;
                case 'S':return 3;
                case 'F':return 4;
                case '-':f=-1;
                default:
                    break;
            }
        for(;isdigit(c);c=getchar())
            num=num*10+c-'0';
        return num*f;
    }
    
    void init()
    {
        srand(INF);        //随机种子 
        tim=1;
        node->flag=1;
        node->son[0]=node->son[1]=node;        //null的左右儿子指向null 
        now_node=root=null=node;
    }
    
    Tree newNode(int key)    //申请新节点 
    {
        //++sum_peo;
        ++now_node;
        now_node->key=key;
        now_node->key_cnt=1;
        now_node->heap_key=rand();
        now_node->size=1;
        now_node->flag=0;
        now_node->son[0]=now_node->son[1]=null;
        now_node->tim=tim;
        return now_node;
    }
    
    void rotate(Tree &root,bool flag)    //旋转,flag==0是左旋,==1是右旋 
    {
        Tree tmp=root->son[!flag];
        root->son[!flag]=tmp->son[flag];
        tmp->son[flag]=root;
        root->size=root->son[0]->size+root->son[1]->size+root->key_cnt;
        tmp->size=tmp->son[0]->size+tmp->son[1]->size+tmp->key_cnt;
        root=tmp;
    }
    
    void insert(Tree &root,int key)
    {
        if(root==null)        //开新的工资档案 
            root=newNode(key);
        else if(key==root->key)        //相同工资人数++ 
        {
            ++root->key_cnt,++root->size;
        }
        else
        {
            bool flag=key<root->key;
            insert(root->son[flag],key);
            ++root->size;
            if(root->heap_key<root->son[flag]->heap_key)
                rotate(root,!flag);
        }
    }
    
    void erase(Tree &root,int key,int num)        //num个员工跳槽 
    {
        if(root==null)
            return;
        if(key!=root->key)
        {
            bool flag=key<root->key;
            erase(root->son[flag],key,num);
            root->size-=num;
        }
        else
        {
            if(root->son[0]==null)
            {
                //change=root;
                //printf("A:  change:%d  root:%d
    ",change,root);
                root=root->son[1];
                //printf("B:  change:%d  root:%d
    ",change,root);
            }
            else if(root->son[1]==null)
            {
                //change=root;
                root=root->son[0];
            }
            else
            {
                bool flag=root->son[0]->heap_key>root->son[1]->heap_key;
                rotate(root,flag);
                erase(root->son[flag],key,num);
                root->size-=num;
            }
        }
    }
    
    int query_num(Tree root,int k)        //询问第k大 
    {
        if(root==null)
            return 0;
        if(k<=root->son[0]->size)
            return query_num(root->son[0],k);
        if(k>root->son[0]->size+root->key_cnt)
            return query_num(root->son[1],k-root->son[0]->size-root->key_cnt);
        return root->key;
    }
    //
    //Tree find(Tree x)
    //{
    //    return x->fa==x?x:x->fa=find(x->fa);
    //}
    
    int main()
    {
        //freopen("233.in","r",stdin);
        //freopen("233.out","w",stdout);
        init();        //别忘调用初始化函数 
        n=read(),minn=read();
        while(n--)
        {
            opt=read(),x=read();
            switch(opt)
            {
                case 1:
                    if(x>=minn)
                        ++sum_peo,        //在职员工人数++ 
                        insert(root,x);
                    break;
                case 2:
                    for(Tree i=node+1;i<=now_node;++i)
                    {
                        if(i->flag==1)    //跳槽了 
                            continue;
                        i->key+=x;        //涨工资 
                    }
                    break;
                case 3:
                    //printf("be:  %d
    ",sum_peo);
                    for(Tree i=node+1;i<=now_node;++i)
                    {
                        if(i->flag==1)        //已经跳槽了 
                            continue;
                        i->key-=x;    //扣工资 
                        if(i->key<minn)
                        {
                            //Tree change=null;
                            //printf("C: change: %d
    ",change);
                            erase(root,i->key,i->key_cnt);
                            sum_peo-=i->key_cnt;    //减去这个工资的人数 
                            leave_peo+=i->key_cnt;    //跳槽人数 
                            i->flag=1;    //标记一下已经跳槽 
                            //printf("D: change: %d
    ",change);
                            //change=null;
                            //printf("E: change: %d
    ",change);
                        }
                    }
                    //printf("af:  %d
    ",sum_peo);
                    break;
                default:
                    //printf("peo: %d
    ",sum_peo);
                    if(x>sum_peo)
                        printf("-1
    ");
                    else printf("%d
    ",query_num(root,x));
            }
        }
        printf("%d",leave_peo);
        return 0;
    }
  • 相关阅读:
    abp(net core)+easyui+efcore实现仓储管理系统——入库管理之一(三十七)
    abp(net core)+easyui+efcore实现仓储管理系统——ABP WebAPI与EasyUI结合增删改查之十(三十六)
    abp(net core)+easyui+efcore实现仓储管理系统——ABP WebAPI与EasyUI结合增删改查之九(三十五)
    abp(net core)+easyui+efcore实现仓储管理系统——ABP WebAPI与EasyUI结合增删改查之八(三十四)
    abp(net core)+easyui+efcore实现仓储管理系统——ABP WebAPI与EasyUI结合增删改查之七(三十三)
    abp(net core)+easyui+efcore实现仓储管理系统——ABP WebAPI与EasyUI结合增删改查之六(三十二)
    abp(net core)+easyui+efcore实现仓储管理系统——ABP WebAPI与EasyUI结合增删改查之五(三十一)
    一个屌丝程序猿的人生(一百一十四)
    一个屌丝程序猿的人生(一百一十三)
    给程序员们以及在外漂泊的同学们普及下户口那点事!
  • 原文地址:https://www.cnblogs.com/lovewhy/p/8463534.html
Copyright © 2011-2022 走看看