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\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 }

时间: 2024-10-19 12:02:18

NOI2004 郁闷的出纳员 Splay的相关文章

【BZOJ1503】 [NOI2004]郁闷的出纳员 splay

splay模板题,都快把我做忧郁了. 由于自己调两个坑点. 1.删除时及时updata 2.Kth 考虑k满足该点的条件即r->ch[1]->size+1<=k && r->ch[1]->size+r->num>=k 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 struct Spla

BZOJ[NOI2004]郁闷的出纳员 | Splay板子题

题目: 洛谷也能评测....还有我wa了10多次的记录233 题解: 不要想得太复杂,搞一个全局变量记录一下工资的改变量Delta,这样可以等询问的时候就输出val+Delta,然后插入的时候插入x-Delta 不要想会不会有员工工资一样,直接插入就好,这样省不少代码量. 对于降工资操作,插入一个min-Delta节点,ans+=左子树大小,右儿子作为新的根节点 直接走的员工不要算ans #include<cstdio> #include<algorithm> #include&l

[BZOJ 1503] [NOI2004] 郁闷的出纳员

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

BZOJ 题目1503: [NOI2004]郁闷的出纳员(SBT+延迟操作)

1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 8058  Solved: 2828 [Submit][Status][Discuss] Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资.如果他心情好,就可能把每位员工的工资加上一个相同的量.反

bzoj 1503郁闷的出纳员(splay)

1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 11759  Solved: 4163[Submit][Status][Discuss] Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资.如果他心情好,就可能把每位员工的工资加上一个相同的量.反之

[BZOJ1503][NOI2004]郁闷的出纳员 无旋Treap

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

1503: [NOI2004]郁闷的出纳员 Treap

1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 6263  Solved: 2190[Submit][Status] Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资.如果他心情好,就可能把每位员工的工资加上一个相同的量.反之,如果心情不好,就可

bzoj1503 [NOI2004]郁闷的出纳员(名次树+懒惰标记)

1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 8705  Solved: 3027[Submit][Status][Discuss] Description OIER 公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是, 我们的老板反复无常,经常调整员工的工资.如果他心情好,就可能把每位员工的工资加上一个相同的量.反

bzoj 1503: [NOI2004]郁闷的出纳员 平衡树

1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 12250  Solved: 4372[Submit][Status][Discuss] Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资.如果他心情好,就可能把每位员工的工资加上一个相同的量.反之