zoukankan      html  css  js  c++  java
  • NOI2004 郁闷的出纳员 Splay

    郁闷的出纳员

    【问题描述】

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

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

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

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

    【输入文件】

    第一行有两个非负整数nminn表示下面有多少条命令,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。

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

    【样例输入】

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

    【样例输出】

    10
    20
    -1
    2

    【约定】

    l  I命令的条数不超过100000

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

    l  F命令的条数不超过100000

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

    l  新员工的工资不超过100000

    【题意】

    要求设计一种数据结构,能够快速进行以上4种操作,完成对整个工资单的动态维护。

    【分析】

    这种动态问题,很明显的要用到动态的数据结构来维护,可以使用一般的线段树或者平衡树进行解决,而本题的特点非常适合Splay的发挥。

    首先是看到A和S命令,都是针对整个工资单中的所有员工进行操作的,因此可以考虑不改变每个员工单独的值(n个员工就要改n次,开玩笑......),而是用另外一个独立的变量把所有的加减操作都记录下来,判断员工出局的时候再结合题目给定的最低值计算出下限。这里要注意的是,但是当一个员工新加入时,之前的调工资操作应该对他是不产生影响的,因为那时候这个人还不在,但是用来记录工资加减的独立变量只有一个,所以在新员工加入的时候要把之前的工资加减情况减掉,这样最后计算时才可以把前面的部分抵消掉。

    另,若一个人的初始工资小于底线,则这个人的离开不算到最后的答案中。

    插入和找第k值都是基本的二叉树很容易解决,删除操作是本题的重点:

    测试模板和修改删除部分花了大把的时间..T_T

    根据上面的思路,用mi表示给定的底线,tot记录工资加减情况,则最后mi-tot就是初始工资的相对底线,每次出现S,也就是减了工资之后,就需要把树中低于mi-tot的所有值都删掉。但是splay在实际使用过程中,若树中存在多个mi-tot的值,则由于中间有各种旋转、splay操作,直接查找mi-tot得到的位置不能够确定剩下的是在左子树还是右子树还是两个都有。于是采取的方案:

    1.搜索mi-tot-1

    2.若不存在,则插入一个mi-tot-1,将其旋转到根,然后把根和左子树都删掉!!!树中剩下的就是大于mi-tot-1,也就是大于等于mi-tot的值了,注意计数时不要忘记这个根是自己加进去的,不要算进去。

    3.若存在mi-tot-1,则同样将根和左子树都删掉,然后在右子树中搜索mi-tot-1,旋转到根删掉,不断重复直到整棵树中不存在mi-tot-1

      1 /* ***********************************************
      2 MYID    : Chen Fan
      3 LANG    : G++
      4 PROG    : cashier
      5 ************************************************ */
      6 
      7 #include <iostream>
      8 #include <cstdio>
      9 #include <cstring>
     10 #include <algorithm>
     11 
     12 using namespace std;
     13 
     14 
     15 #define MAXN 100010
     16 
     17 int sons[MAXN][2];
     18 int father[MAXN],size[MAXN],data[MAXN];
     19 int spt=0,spttail=0,tot=0,men=0;
     20 
     21 void rotate(int x,int w) //rotate(node,0/1)
     22 {
     23     int y=father[x];
     24     sons[y][1-w]=sons[x][w];
     25     if (sons[x][w]) father[sons[x][w]]=y;
     26 
     27     father[x]=father[y];
     28     if (father[y])
     29     if (y==sons[father[y]][0]) sons[father[y]][0]=x;
     30     else sons[father[y]][1]=x;
     31 
     32     sons[x][w]=y;
     33     father[y]=x;
     34 
     35     size[x]=size[y];
     36     size[y]=size[sons[y][0]]+size[sons[y][1]]+1;
     37 }
     38 
     39 void splay(int x,int y) //splay(node,position)
     40 {
     41     if (!x) return ;
     42     while(father[x]!=y)
     43     {
     44         if (father[father[x]]==y)
     45             if (x==sons[father[x]][0]) rotate(x,1);
     46             else rotate(x,0);
     47         else 
     48             if (father[x]==sons[father[father[x]]][0])
     49                 if (x==sons[father[x]][0])
     50                 {
     51                     rotate(father[x],1);
     52                     rotate(x,1);
     53                 } else 
     54                 {
     55                     rotate(x,0);
     56                     rotate(x,1);
     57                 }
     58             else 
     59                 if (x==sons[father[x]][1])
     60                 {
     61                     rotate(father[x],0);
     62                     rotate(x,0);
     63                 } else 
     64                 {
     65                     rotate(x,1);
     66                     rotate(x,0);
     67                 }
     68     }
     69     if (!y) spt=x;
     70 }
     71 
     72 void search(int x,int w)
     73 {
     74     while(data[x]!=w)
     75     {
     76         if (w<data[x])
     77         {
     78             if (sons[x][0]) x=sons[x][0];
     79             else break;
     80         } else if (w>data[x])
     81         {
     82             if (sons[x][1]) x=sons[x][1];
     83             else break;
     84         }
     85     }
     86     splay(x,0);
     87 }
     88 
     89 void insert(int w) //insert(value)
     90 {
     91     spttail++;
     92     data[spttail]=w;
     93     size[spttail]=1;
     94     sons[spttail][0]=0;
     95     sons[spttail][1]=0;
     96     if (!spt)
     97     {
     98         father[spttail]=0;
     99         spt=spttail;
    100     } else 
    101     {
    102         int x=spt;
    103         while(1)
    104         {
    105             size[x]++;
    106             if (w<data[x])
    107                 if (sons[x][0]) x=sons[x][0];
    108                 else break;
    109             else 
    110                 if (sons[x][1]) x=sons[x][1];
    111                 else break;
    112         }
    113         father[spttail]=x;
    114         if (w<data[x]) sons[x][0]=spttail;
    115         else sons[x][1]=spttail;
    116         splay(spttail,0);
    117     }
    118 }
    119 
    120 void select(int x,int v) //select(root,k)
    121 {
    122     while(v!=size[sons[x][0]]+1)
    123     {
    124         if (v<=size[sons[x][0]]) x=sons[x][0];
    125         else 
    126         {
    127             v-=size[sons[x][0]]+1;
    128             x=sons[x][1];
    129         }
    130     }
    131     splay(x,0);
    132 }
    133 
    134 int main()
    135 {
    136     freopen("cashier.in","r",stdin);
    137     freopen("cashier.out","w",stdout);
    138     
    139     int n,mi;
    140     scanf("%d%d",&n,&mi);
    141 
    142     spt=0;
    143     spttail=0;
    144     tot=0;
    145     men=0;
    146 
    147     for (int i=1;i<=n;i++)
    148     {
    149         char c;
    150         c=getchar();
    151         while(c!='I'&&c!='A'&&c!='S'&&c!='F') c=getchar();
    152         int k;
    153         scanf("%d",&k);
    154 
    155         if (c=='I')
    156         {
    157             if (k>=mi) insert(k-tot);
    158         } else 
    159         if (c=='A')
    160         {
    161             tot+=k;
    162         } else
    163         if (c=='S')
    164         {
    165             tot-=k;
    166 
    167             search(spt,mi-tot-1);
    168             if (data[spt]!=mi-tot-1)
    169             {
    170                 insert(mi-tot-1);
    171                 men+=size[sons[spt][0]];
    172                 spt=sons[spt][1];
    173                 father[spt]=0;
    174             } else
    175             {
    176                 men+=size[sons[spt][0]]+1;
    177                 spt=sons[spt][1];
    178                 father[spt]=0;
    179                 search(spt,mi-tot-1);
    180                 while(data[spt]==mi-tot-1)
    181                 {
    182                     men++;
    183                     spt=sons[spt][1];
    184                     father[spt]=0;
    185                     search(spt,mi-tot-1);
    186                 }
    187             }
    188         } else 
    189         {
    190             if (k>size[spt]) printf("-1
    ");
    191             else 
    192             {
    193                 select(spt,size[spt]-k+1);
    194                 printf("%d
    ",data[spt]+tot);
    195             }
    196         }
    197 
    198         //printf("Size:%d mi-tot+1:%d
    ",size[spt],mi-tot); //debug
    199     }
    200 
    201     //printf("%d
    ",men-size[spt]);
    202     printf("%d
    ",men);
    203 
    204     return 0;
    205 }
    View Code
  • 相关阅读:
    做开发的童鞋应该都了解这几款软件
    给文件对比工具自定义快捷键的方法
    C/C++ 编程有哪些值得推荐的辅助工具
    如何用Beyond Compare修改对比文件颜色
    据说这些工具可以提高程序员的工作效率
    遇到Beyond Compare禁止编辑该怎么办
    BZOJ
    周三
    大总结
    周二上午
  • 原文地址:https://www.cnblogs.com/jcf94/p/4333425.html
Copyright © 2011-2022 走看看