Codeforces D. Multiset (树状数组 & 二分)(Round 87 Rated for Div.2)

传送门

题意: 现有一个多元集合,你有如下两种操作:

  • 将数k加入多元集合中
  • 找到多元集合升序第k位,并将其删除
    最后打印出集合中的任意元素,若集合为空直接输出0。
    在这里插入图片描述

思路:

  • 利用树状数组统计数值下标的个数,
  • 通过树状数组的前缀和性质再使用二分锁定第k个数的位置。

代码实现:

#include<bits/stdc++.h>
#define lowbit(x) (x &(-x))
using namespace std;
const int  N = 1e6 + 500;
int n, q, x, tr[N];

void add(int k, int d)
{
    while(k < N){
        tr[k] += d;
        k += lowbit(k);
    }
}

int ask(int x)
{
    int sum = 0;
    while(x){
        sum += tr[x];
        x -= lowbit(x);
    }
    return sum;
}

int Find(int x,int k) {
    int l = x + 1, r = N, ans = -1;
    while(l <= r) {
        int mid = (l + r) >> 1;
        if(ask(mid) - ask(x) >= k) r = mid - 1, ans = mid;
        else l = mid + 1;
    }
    return ans;
}

signed main()
{
    scanf("%d%d", &n, &q);
    for(int i = 1; i <= n; i ++) {
        scanf("%d", &x);
        x += 100;
        add(x, 1);
    }

    while(q --){
        scanf("%d", &x);
        if(x <= 0){
            x = -x;
            int tmp = Find(1,x);
            if(tmp == -1) continue;
            add(tmp, -1);
        }
        else add(x + 100, 1);
    }
    int ok = 1;
    //如果集合还存在元素就输出第一个元素
    for(int i = 1; i <= n; i ++) {
        if(ask(i + 100) - ask(i + 99)) {
            printf("%d\n", i);
            ok = 0;
            break;
        }
    }
    if(ok) printf("0\n");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值