题目链接https://vjudge.net/problem/HYSBZ-1503
分析
此题中描述的各种命令可以用Treap来高效实现.
对于I k命令, 直接调用Treap的插入操作即可.
对于F k命令, 也可直接调用Treap的查询第k小的操作.
对于A k和S k命令, 假如直接暴力修改整棵树的结点, 那么会超时. 其中一个优化方法就是将结点中存的绝对工资改为相对工资, 再设立一个基准工资(0工资点) base, 当我们执行A k命令时, 令base = base + k, 当我们执行S k命令时, 则令base = base - k, 这样, 实际工资 = 相对工资 + base. 当我们执行S k命令时, 可能需要删去结点, 可以使用优先队列来优化.
代码
#include<bits/stdc++.h>
#define x first
#define y second
#define ok puts("ok");
using namespace std;
typedef long long ll;
typedef vector<int> vi;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const double PI = acos(-1.0);
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;
const int N=1e5+9;
const int shift=1e3+9;
const double Eps=1e-7;
char c;
int n, mi, t, cnt, base;
//Treap结点
struct node {
node *left, *right; //左儿子, 右儿子
int salary, weight, size, fix; //薪水, 具有同一薪水的人数(一个优化), 子树大小, 修正值
inline int lsize() {return left?left->size:0;} //求左儿子的大小
inline int rsize() {return right?right->size:0;} //求右儿子的大小
};
//左旋
void leftRotate(node *&a) {
node *b = a->right;
a->right = b->left;
b->left = a;
a = b;
b = a->left;
b->size = b->lsize() + b->rsize() + b->weight; //更新结点的子树大小
a->size = a->lsize() + a->rsize() + a->weight;
}
//右旋
void rightRotate(node *&a) {
node *b = a->left;
a->left = b->right;
b->right = a;
a = b;
b = a->right;
b->size = b->lsize() + b->rsize() + b->weight; //更新结点的子树大小
a->size = a->lsize() + a->rsize() + a->weight;
}
//插入
void insert(node *&p, int salary) {
if(!p) { //创建新结点
p = new node;
p->fix = rand();
p->salary = salary;
p->size = p->weight = 1;
p->left = p->right = NULL;
}
else if(p->salary == salary) { //假如已经存在有同一薪水的结点, 则让该结点的权重加一
p->weight++;
}
else if(salary < p->salary) {
insert(p->left, salary);
if(p->left->fix < p->fix)
rightRotate(p);
}
else {
insert(p->right, salary);
if(p->right->fix < p->fix)
leftRotate(p);
}
p->size = p->lsize() + p->rsize() + p->weight;
}
//删除
void del(node *&p, int salary) {
if(p->salary == salary) {
if(p->weight > 1) { //假如存在结点, 且该结点的权重大于1, 则仅让该点权重减一
p->weight--;
}
else if(!p->left || !p->right) { //该点是叶结点或链结点
node *t = p;
if(!p->right)
p = p->left;
else
p = p->right;
delete t;
}
else if(p->left->fix < p->right->fix){ //该点有两个儿子
rightRotate(p);
del(p, salary);
}
else {
leftRotate(p);
del(p, salary);
}
}
else if(salary < p->salary) //递归查找删除
del(p->left, salary);
else
del(p->right, salary);
if(p) //更新子树大小
p->size = p->lsize() + p->rsize() + p->weight;
}
//查找薪资排名第k小的
int findK(node *&p, int k) {
if(k <= p->lsize())
return findK(p->left, k);
else if(k > p->lsize() + p->weight)
return findK(p->right, k-(p->lsize()+p->weight));
else
return p->salary;
}
int main(void) {
//if(fopen("in", "r")!=NULL) {freopen("in", "r", stdin); freopen("out", "w", stdout);}
node *root = NULL;
scanf("%d%d", &n, &mi);
priority_queue<int, vi, greater<int> > que;
while(n--) {
getchar();
c = getchar();
scanf("%d", &t);
if(c == 'I') {
if(t < mi) continue;
insert(root, t-base);
que.push(t-base);
}
else if(c == 'A') {
base += t;
}
else if(c == 'S') {
base -= t;
while(!que.empty()) {
int t1 = que.top();
if(t1 + base < mi) {
que.pop();
del(root, t1);
cnt++;
}
else
break;
}
}
else { //查询
if(root == NULL || root->size < t) {
printf("-1\n");
continue;
}
int ans = findK(root, root->size-t+1);
printf("%d\n", ans + base);
}
}
printf("%d\n",cnt);
return 0;
}