【BZOJ1503】【NOI2004】郁闷的出纳员
【问题描述】
OIER公司是一家大型专业化软件公司,有着数以万计的员工。作为一名出纳员,我的任务之一便是统计每位员工的工资。这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资。如果他心情好,就可能把每位员工的工资加上一个相同的量。反之,如果心情不好,就可能把他们的工资扣除一个相同的量。 工资的频繁调整很让员工反感,尤其是集体扣除工资的时候,一旦某位员工发现自己的工资已经低于了合同规定的工资下界,他就会立刻气愤地离开公司,并且再也不会回来了。每位员工的工资下界都是统一规定的。每当一个人离开公司,我就要从电脑中把他的工资档案删去,同样,每当公司招聘了一位新员工,我就得为他新建一个工资档案。 老板经常到我这边来询问工资情况,他并不问具体某位员工的工资情况,而是问现在工资第k多的员工拿多少工资。 请你编一个工资统计程序。
输入:
【分析】
平衡树。我写splay。
工资的加减,由于是对于所有员工的,所以不用修改每个员工的值,只要把总共的变化值delt记下来就行了。加入员工的时候,把初始工资减去delt。查询时第k多的工资,把工资下界减去delt。
查询第k多的工资,也很简单。只要在平衡树每个节点多记一个参数,表示以它为根的子树的节点数。把第k多转换成第K小。然后从根开始遍历,如果当前点的左儿子子树节点数等于K-1的话,就找到了。如果小于,那么往左走。反之往右走。往右走记得要把K扣除比它小的数的数目,即当前点左儿子子树节点数+1.
【代码】
写得一向龊的splay。。。
/************************************************************** Problem: 1503 User: N_C_Derek Language: C++ Result: Accepted Time:760 ms Memory:5180 kb ****************************************************************/ //noi2004郁闷的出纳员 #include <cstring> #include <iostream> #include <cstdio> #include <algorithm> #include <cmath> int n,m,Min,delt,root,t,ans; struct node { int l,r,num,father,data; }tree[200001]; void zig(int x) { int p = tree[x].father; tree[x].father = tree[p].father; if (tree[p].father != 0) { if (tree[tree[p].father].l == p) tree[tree[p].father].l = x; else tree[tree[p].father].r = x; } tree[p].father = x; tree[tree[x].r].father = p; tree[p].l = tree[x].r; tree[x].r = p; tree[p].num -= tree[tree[x].l].num + 1; tree[x].num += tree[tree[p].r].num + 1; } void zag(int x) { int p = tree[x].father; tree[x].father = tree[p].father; if (tree[p].father != 0) { if (tree[tree[p].father].l == p) tree[tree[p].father].l = x; else tree[tree[p].father].r = x; } tree[p].father = x; tree[tree[x].l].father = p; tree[p].r = tree[x].l; tree[x].l = p; tree[p].num -= tree[tree[x].r].num + 1; tree[x].num += tree[tree[p].l].num + 1; } void splay(int x) { while (tree[x].father) { int j = tree[x].father; if (tree[j].father == 0) { if (tree[j].l == x) zig(x);else zag(x); break; } if (tree[tree[j].father].l == j) { if (tree[j].l == x) { zig(j); zig(x); } else { zag(x);zig(x); } }else { if (tree[j].r == x) { zag(j); zag(x); } else { zig(x);zag(x); } } } root = x; } void Insert(int x) { if (!root) {tree[++t].data = x;tree[t].num = 1;root = t;return;} int i = root,j; while (i) { j = i; tree[i].num ++; if (x < tree[i].data) i = tree[i].l; else i = tree[i].r; } if (x < tree[j].data) tree[j].l = ++t; else tree[j].r = ++t; tree[t].father = j; tree[t].data = x; tree[t].num = 1; splay(t); } void find(int k) { if (k < 1) { printf("-1\n"); return; } int i = root; while (tree[i].l || tree[i].r) { if (k == tree[tree[i].l].num + 1) break; if (k < tree[tree[i].l].num + 1) i = tree[i].l; else { k -= tree[tree[i].l].num + 1; i = tree[i].r; } } printf("%d\n",tree[i].data + delt); } void Delete(int k) { int x = root; int xx= 0; while (x) { if (tree[x].data < k) {xx = x;x = tree[x].r;} else x = tree[x].l; } if (xx == 0) return; splay(xx); if (tree[xx].r == 0) {ans += tree[xx].num;root = 0;return;} ans += tree[tree[xx].l].num + 1; root = tree[xx].r;tree[root].father = 0; } int main() { scanf("%d %d",&m,&Min); for (int i = 1;i <= m;i ++) { char ch; int k; scanf("\n"); scanf("%c %d",&ch,&k); if (ch == 'I') { if (k >= Min) Insert(k - delt); } else if (ch == 'F') { find(tree[root].num - k + 1); } else if (ch == 'S') { delt -= k; Delete(Min - delt); } else delt += k; } printf("%d",ans); }