码迷,mamicode.com
首页 > 其他好文 > 详细

NOI2004 郁闷的出纳员 Splay

时间:2015-03-12 22:03:25      阅读:242      评论:0      收藏:0      [点我收藏+]

标签:

郁闷的出纳员

 

【问题描述】

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\n");
191             else 
192             {
193                 select(spt,size[spt]-k+1);
194                 printf("%d\n",data[spt]+tot);
195             }
196         }
197 
198         //printf("Size:%d mi-tot+1:%d\n",size[spt],mi-tot); //debug
199     }
200 
201     //printf("%d\n",men-size[spt]);
202     printf("%d\n",men);
203 
204     return 0;
205 }
View Code

 

NOI2004 郁闷的出纳员 Splay

标签:

原文地址:http://www.cnblogs.com/jcf94/p/4333425.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!