题意:
模拟一个multiset
,两种操作:
- 插入一个数 k k k
- 删除当前
multiset
中第 k k k大的数
最后经过一系列操作后输出multiset
中的数。
题解:
插入数的话可以用树状数组去维护每个数的个数。
删除操作的话可以通过倍增二分的方式去查找树状数组中
[
0...
i
d
x
]
[0...idx]
[0...idx]的最大的那个
i
d
x
idx
idx使得区间和小于
k
k
k。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1048576; // 二进制刚好是100000
int c[maxn+1];
typedef long long ll;
int lowbit(int a) {
return a & (-a);
}
void update(int x, int val) {
while (x <= maxn) {
c[x] += val;
x += lowbit(x);
}
}
int bsearch(int x) {
if (x == 0) return 0;
int ptr = 0;
// 只有maxn刚好是2^k时才可以这么用,刚好利用了树状数组的二进制性质
// ptr代表了当前的下标,[0,ptr]之间的和都已经被计算了
for (int i = maxn/2; i >= 1; i >>= 1) {
if (c[ptr+i] < x) {
// 这是[ptr,ptr+i]这一段
x -= c[ptr+i];
ptr += i;
}
}
return ptr+1;
}
int main() {
cin.tie(0);
ios_base::sync_with_stdio(false);
int n, q;
cin >> n >> q;
for (int i = 0; i < n; i++) {
int a;
cin >> a;
update(a, 1);
}
while (q--) {
int k;
cin >> k;
if (k > 0) {
update(k, 1);
} else {
k = -k;
int ptr = bsearch(k);
update(ptr, -1);
}
}
for (int i = 1; i < maxn; i++) {
if (c[i]) {
cout << i << endl;
return 0;
}
}
cout << 0 << endl;
}