线段树最常见的每个节点是存未知的信息,但这题不一样,建立线段树的节点是保存数值的信息,这题每个节点记录的是出现的次数。
先通过原来"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;
}