题意:维护一个可重集,支持动态插入、查询第k大、给所有数加上或减去一个值,一旦某数小于常数min立即删除,如果插入的数小于min则忽略。最后输出删除的数的个数。 给整棵树打标记即可。原题描述不清,如果插入的数小于min,不纳入最后的统计。
{% raw %}
#include <cstdio>
#include <cstdlib>
const int MAX_N = 1e5 + 1, inf = 1<<30;
struct Node {
Node* ch[2];
int v, r, s;
void up()
{
s = ch[0]->s + ch[1]->s + 1;
}
} nodes[MAX_N], * null = nodes, * root = null;
namespace Treap {
Node* new_node(int v)
{
static Node* cur = nodes+1;
*cur = (Node){{null, null}, v, rand(), 1};
return cur++;
}
void rotate(Node* &x, int d)
{
Node* y = x->ch[d];
x->ch[d] = y->ch[d^1];
y->ch[d^1] = x;
x->up();
y->up();
x = y;
}
void insert(Node* &x, int v)
{
if (x == null)
x = new_node(v);
else {
int d = v > x->v;
insert(x->ch[d], v);
if (x->ch[d]->r > x->r)
rotate(x, d);
else
x->up();
}
}
void remove(Node* &x, int v)
{
if (x == null)
return;
remove(x->ch[0], v);
if (x->v < v) {
x = x->ch[1];
remove(x, v);
}
if (x != null)
x->up();
}
int kth(Node* x, int k)
{
if (k > x->s)
return -inf;
while (x != null) {
int s = x->ch[1]->s;
if (s+1 == k)
return x->v;
if (k <= s)
x = x->ch[1];
else {
k -= s+1;
x = x->ch[0];
}
}
}
}
int main()
{
srand(65535);
int n, mn, a = 0, cnt = 0;
scanf("%d %d", &n, &mn);
while (n--) {
char c;
int k, q;
scanf(" %c %d", &c, &k);
using namespace Treap;
switch (c) {
case 'I':
if (k >= mn) {
++cnt;
insert(root, k-a);
}
break;
case 'A':
a += k;
break;
case 'S':
a -= k;
remove(root, mn-a);
break;
case 'F':
q = kth(root, k);
printf("%d\n", q == -inf ? -1 : q+a);
}
}
printf("%d\n", cnt - root->s);
return 0;
}
{% endraw %}