洛谷 P1486 [NOI2004] 郁闷的出纳员
Description
Solution
无旋\(treap\) (\(fhq-treap\))
如果有不会 \(fhq-treap\) 的同学,可以看我的博客 浅谈 fhq-treap(无旋treap)
下面我们来看一看这道题。
发现 新建工资档案 和 查询第 \(k\) 多工资 都是板子。
那这个整体加和整体减如何处理呢?
其实很简单。
我们记录一个变量 \(delta\) 加上或减去题目中输入的数值就好。
进行删除操作时,我们把工资小于等于 \(mins - delta - 1\) 的员工删去即可。
查询时,输出查出来的工资加上 \(delta\) 即可。
注意:题目要求查询第 \(k\) 多工资,而我们只能查询第 \(k\) 小,要稍微转换一下,改成查询 \(n - k + 1\)。
具体看代码吧。
Code
#include <bits/stdc++.h>
#define ls(x) t[x].ch[0]
#define rs(x) t[x].ch[1]
using namespace std;
const int N = 3e5 + 10;
struct Treap{
int ch[2], siz, val, wei;
}t[N];
int n, mins, root, tot, delta, sum;
int a, b, c;
inline int read(){
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
inline void pushup(int x){
t[x].siz = t[ls(x)].siz + t[rs(x)].siz + 1;
}
inline void split(int x, int k, int &a, int &b){
if(!x){
a = b = 0;
return;
}
if(t[x].val <= k){
a = x;
split(rs(x), k, rs(x), b);
}else{
b = x;
split(ls(x), k, a, ls(x));
}
pushup(x);
}
inline int merge(int x, int y){
if(!x || !y) return x | y;
if(t[x].wei <= t[y].wei){
rs(x) = merge(rs(x), y);
pushup(x);
return x;
}else{
ls(y) = merge(x, ls(y));
pushup(y);
return y;
}
}
inline int newnode(int k){
t[++tot].val = k, t[tot].siz = 1, t[tot].wei = rand();
return tot;
}
inline void insert(int k){
split(root, k, a, b);
root = merge(a, merge(newnode(k), b));
}
inline void remove(){
split(root, mins - delta - 1, a, b);
root = b;
sum += t[a].siz;
}
inline int query_val(int x, int k){
if(k == t[ls(x)].siz + 1) return t[x].val;
if(k <= t[ls(x)].siz) return query_val(ls(x), k);
else return query_val(rs(x), k - t[ls(x)].siz - 1);
}
int main(){
n = read(), mins = read();
char op;
int x;
for(int i = 1; i <= n; i++){
cin>>op;
x = read();
if(op == 'I' && x >= mins) x -= delta, insert(x);
if(op == 'A') delta += x;
if(op == 'S') delta -= x, remove();
if(op == 'F'){
if(t[root].siz < x) puts("-1");
else printf("%d\n", query_val(root, t[root].siz - x + 1) + delta); //注意题目查询第 k 大,就是第 n - k + 1 小
}
}
printf("%d\n", sum);
return 0;
}