对于 2,3 操作,用权值线段树处理
对于 4,5 操作,用 std::multiset
处理
注意 s.upper_bound
和 upper_bound
的区别,后者复杂度爆炸
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1000005;
const int M = 10000005;
int a[M], ch[M][2], t1, t2, t3, n = 1e9 + 1, m, ind = 1;
void modify(int p, int l, int r, int pos, int key) {
a[p] += key;
if (l < r) {
if (pos <= (l + r) / 2) {
if (ch[p][0] == 0)
ch[p][0] = ++ind;
modify(ch[p][0], l, (l + r) / 2, pos, key);
} else {
if (ch[p][1] == 0)
ch[p][1] = ++ind;
modify(ch[p][1], (l + r) / 2 + 1, r, pos, key);
}
}
}
int query(int p, int l, int r, int ql, int qr) {
if (l > qr || r < ql || p == 0)
return 0;
if (l >= ql && r <= qr)
return a[p];
return query(ch[p][0], l, (l + r) / 2, ql, qr) + query(ch[p][1], (l + r) / 2 + 1, r, ql, qr);
}
int kth(int p, int l, int r, int k) {
if (a[p] < k)
return 0;
if (l == r)
return l;
if (a[ch[p][0]] < k)
return kth(ch[p][1], (l + r) / 2 + 1, r, k - a[ch[p][0]]);
return kth(ch[p][0], l, (l + r) / 2, k);
}
int find(int x) {
int p = 1;
int l = 1, r = n;
while (p && l < r) {
if (x <= (l + r) / 2)
r = (l + r) / 2, p = ch[p][0];
else
l = (l + r) / 2 + 1, p = ch[p][1];
}
return p;
}
void insert(int x) { modify(1, 1, n, x, 1); }
void remove(int x) { modify(1, 1, n, x, -1); }
int kth(int k) { return kth(1, 1, n, k); }
int getrank(int x) { return query(1, 1, n, 1, x - 1); }
multiset<int> s, u;
signed main() {
ios::sync_with_stdio(false);
scanf("%lld", &m);
while (m--) {
scanf("%lld%lld", &t1, &t2);
switch (t1) {
case 0:
insert(t2 + 1);
s.insert(t2);
u.insert(-t2);
break;
case 1:
remove(t2 + 1);
s.erase(s.find(t2));
u.erase(u.find(-t2));
break;
case 2:
printf("%lld
", kth(t2) - 1);
break;
case 3:
printf("%lld
", getrank(t2 + 1));
break;
case 4: {
auto tmp1 = u.upper_bound(-t2);
if (tmp1 == u.end())
puts("-1");
else
printf("%lld
", -*tmp1);
} break;
case 5: {
auto tmp2 = s.upper_bound(t2);
if (tmp2 == s.end())
puts("-1");
else
printf("%lld
", *tmp2);
} break;
}
}
}