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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章