Educational Codeforces Round 87 (Rated for Div. 2) D. Multiset
题意:一个很有意思的题,空间限制28mb。给一个数组a,和q次操作p[i],p[i]>0时表示将p[i]插入到集合a中,p[i]<0时表示删除升序abs(p[i])位置的数,然后输出数组中任意一个数。
思路:Note that the memory limit is unusual. 28mb的内存把树状数组卡到MLE的边缘,线段树存不下。常规写法是树状数组+二分。但补题的时候找到了一个很惊艳的解法。二分0~max,check mid的位置。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e6 + 100;
const int mod = 1e9 + 7;
int n, q;
int a[maxn], p[maxn];
int check(int x) {
int cnt = 0;
for (int i = 1; i <= n; i++) if (a[i] <= x) cnt++; //统计小于x的个数
for (int i = 1; i <= q; i++) {
if (p[i] < 0 && -p[i] <= cnt) cnt--; //如果对数组进行了删除操作
else if (p[i] > 0 && p[i] <= x) cnt++; //如果加入了一个小于x的新的数
}
return cnt;
}
int main() {
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
for (int i = 1; i <= q; i++) scanf("%d", &p[i]);
int l = 1, r = 2e6;
while (l <= r) {
int mid = l + r >> 1;
if (check(mid) > 0) r = mid - 1;
else l = mid + 1;
}
if (l > 2e6) l = 0;
printf("%d\n", l);
return 0;
}