【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。
输出文件的最后一行包含一个整数,为离开公司的员工的总数。
【分析】
一道很简单的平衡树的题目,用Treap、Splay、块状链表和线段树都可过,
我用Treap过的,我比较懒,甚至连元素判重都没有加,将就一下吧。
1 #include <cstdlib> 2 #include <iostream> 3 #include <cstring> 4 #include <cmath> 5 #include <cstdio> 6 #include <ctime> 7 #include <queue> 8 #define NEW(p) p=&mem[++size_point];p->size=0;p->key=RAND*RAND;p->money=-0x7fffffff 9 const long long RAND=32768; 10 using namespace std; 11 //随机 12 inline long long bigRand() {return (rand()*RAND)+rand();} 13 14 int Min,size_point=0,lj=0; 15 struct node 16 { 17 node *left,*right; 18 long long key; 19 int money;//最小堆键值 20 int size; 21 void update() 22 { 23 //注意要加上自身 24 size=left->size+right->size+1; 25 } 26 }mem[1000000],*null,*root; 27 void rot_l(node *&t)//左旋 28 { 29 node *p=t->right; 30 t->right=p->left; 31 p->left=t; 32 t->update(); 33 p->update(); 34 t=p; 35 } 36 void rot_r(node *&t)//右旋 37 { 38 node *p=t->left; 39 t->left=p->right; 40 p->right=t; 41 t->update(); 42 p->update(); 43 t=p; 44 } 45 //插入元素 46 void insert(node *&t,int value) 47 { 48 if (t==null) 49 { 50 node*p; 51 NEW(p); 52 p->size=1;p->key=bigRand(); 53 p->money=value; 54 p->left=null; 55 p->right=null; 56 t=p; 57 return; 58 } 59 if (value>t->money) 60 { 61 insert(t->right,value); 62 if (t->right->key<t->key) rot_l(t); 63 else t->update(); 64 } 65 else 66 { 67 insert(t->left,value); 68 if (t->left->key<t->key) rot_r(t); 69 else t->update(); 70 } 71 } 72 void erase(node *&t,int value)//删除数 73 { 74 if (t==null) return; 75 if (t->money==value) 76 { 77 //dir为1,方向right 78 if (t->right->key<t->left->key) 79 { 80 if (t->right==null) 81 { 82 t=null; 83 return; 84 } 85 rot_l(t); 86 erase(t->left,value); 87 t->update(); 88 return; 89 } 90 else 91 { 92 if (t->left==null) 93 { 94 t=null; 95 return; 96 } 97 rot_r(t); 98 erase(t->right,value); 99 t->update(); 100 return; 101 } 102 103 } 104 if (value>t->money)//在前面找 105 { 106 erase(t->right,value); 107 t->update(); 108 } 109 else 110 { 111 erase(t->left,value); 112 t->update(); 113 } 114 } 115 //查找第k小的数 116 int find(node *t,int k) 117 { 118 if (k<=t->left->size) return find(t->left,k); 119 else if (k>(t->left->size+1)) 120 return find(t->right,k-(t->left->size+1)); 121 return t->money; 122 } 123 124 void add(node *&t,int num) 125 { 126 if (t==null) return; 127 128 int rem=-1; 129 while (rem!=lj && t!=null) 130 { 131 rem=lj; 132 t->money+=num; 133 if (t->money<Min) 134 { 135 erase(root,t->money); 136 lj++; 137 } 138 } 139 add(t->left,num); 140 add(t->right,num); 141 } 142 void print(node *&t)//打印 143 { 144 if (t==null) return; 145 print(t->left); 146 printf("%d\n",t->money); 147 print(t->right); 148 } 149 int main() 150 { 151 int i,n; 152 memset(mem,0,sizeof(mem)); 153 NEW(null); 154 root=null; 155 null->left=null; 156 null->right=null; 157 scanf("%d%d",&n,&Min); 158 for (i=1;i<=n;i++) 159 { 160 char order;int num; 161 getchar(); 162 scanf("%c%d",&order,&num); 163 if (order=='I' && num>=Min) insert(root,num); 164 else if (order=='F') 165 { 166 if (num>root->size) printf("-1\n"); 167 else printf("%d\n",find(root,root->size-num+1)); 168 } 169 else if (order=='A') add(root,num); 170 else if (order=='S') add(root,-num); 171 } 172 printf("%d",lj); 173 return 0; 174 }