【第一周推荐题】Educational Codeforces Round 87 (Rated for Div. 2) D. Multiset

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;
}

猜你喜欢

转载自blog.csdn.net/weixin_43269437/article/details/107290008