線段樹最常見的每個節點是存未知的信息,但這題不一樣,建立線段樹的節點是保存數值的信息,這題每個節點記錄的是出現的次數。
先通過原來"multiset"裏有的元素更新一下線段樹。
插入:插入num,把區間[num,num]的節點+1,然後pushUp。
查找: 查找第num大的數,看左子樹節點存的值是不是大於num,大於num的話就往左子樹找,否則num = num - 左子樹的值,然後往右子樹找,l == r時return l。
單個刪除:
先查找到第k大的數num,然後對區間[num, num]的節點-1,然後pushUp。
#include <bits/stdc++.h>
using namespace std;
const int maxn = (int)1e6+100;
int n, q, tVal[maxn<<2], a[maxn];
void pushUp(int node) {
tVal[node] = tVal[node<<1] + tVal[node<<1|1];
}
void build(int node, int l, int r) {
if (l == r) {
tVal[node] = 0;
return;
}
int mid = (l + r) >> 1;
build(node<<1, l, mid);
build(node<<1|1, mid+1, r);
pushUp(node);
}
void update(int node, int l, int r, int num, int val) {
if (l == r) {
tVal[node] += val;
return;
}
int mid = (l + r) >> 1;
if (num <= mid) update(node<<1, l, mid, num, val);
else update(node<<1|1, mid+1, r, num, val);
pushUp(node);
}
int query(int node, int l, int r, int num) {
if (l == r) return l;
int mid = (l + r) >> 1;
if (tVal[node<<1] >= num) return query(node<<1, l, mid, num);
else return query(node<<1|1, mid+1, r, num - tVal[node<<1]);
}
void solve(int node, int l, int r) {
if (l == r) {
cout << l << '\n';
return;
}
int mid = (l + r) >> 1;
if (tVal[node<<1]) solve(node<<1, l, mid);
else solve(node<<1|1, mid+1, r);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.precision(10);
cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
cin >> n >> q;
build(1, 1, n);
for (int i = 1; i <= n; ++i) {
cin >> a[i];
update(1, 1, n, a[i], 1);
}
for (int i = 0; i < q; ++i) {
int k;
cin >> k;
if (k > 0) {
update(1, 1, n, k, 1);
} else {
k = -k;
int nu = query(1, 1, n, k);
update(1, 1, n, nu, -1);
}
}
if (!tVal[1]) cout << 0 << '\n';
else solve(1, 1, n);
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}