You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
|
|
#include <bits/stdc++.h>
|
|
|
|
|
using namespace std;
|
|
|
|
|
// 571 ms
|
|
|
|
|
const int N = 3200100;
|
|
|
|
|
const int base = 1e7;
|
|
|
|
|
|
|
|
|
|
// 01Trie树
|
|
|
|
|
int tr[N][2];
|
|
|
|
|
int root = 1; //根是1号点
|
|
|
|
|
int idx = 1; //节点号计数器
|
|
|
|
|
int cnt[N]; //结点p的子结点的个数
|
|
|
|
|
|
|
|
|
|
//插入
|
|
|
|
|
void insert(int x, int t) {
|
|
|
|
|
x += base; //保证输入非负
|
|
|
|
|
int p = root;
|
|
|
|
|
for (int i = 31; ~i; i--) { //从高位到低位
|
|
|
|
|
int c = x >> i & 1; //计算x在第i位是0还是1
|
|
|
|
|
if (!tr[p][c]) tr[p][c] = ++idx; //如果想走的位置不存在,则创建之,++idx为新创建的节点的编号
|
|
|
|
|
p = tr[p][c]; //游标p继续前行
|
|
|
|
|
//这句是迎合本题特殊加入的记录数据
|
|
|
|
|
cnt[p] += t; //以p为根的子树中节点个数
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//获取小于数x的个数
|
|
|
|
|
int rnk(int x) {
|
|
|
|
|
x += base; //保证输入非负
|
|
|
|
|
int p = root;
|
|
|
|
|
int res = 0;
|
|
|
|
|
for (int i = 31; ~i; i--) { //从高位到低位
|
|
|
|
|
int c = x >> i & 1; //计算x在第i位是0还是1
|
|
|
|
|
if (c) res += cnt[tr[p][0]]; //当该位为1时,找其他的该位为0的数的个数,就是严格小于这个数的个数了
|
|
|
|
|
p = tr[p][c]; //游标p继续前行
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//获取第k位置的数字
|
|
|
|
|
int find_kth(int k) {
|
|
|
|
|
int p = root;
|
|
|
|
|
int res = 0;
|
|
|
|
|
for (int i = 31; ~i; i--) { // ~i 表示 i>=0
|
|
|
|
|
if (k > cnt[tr[p][0]]) //在右手边
|
|
|
|
|
res += (1 << i), k -= cnt[tr[p][0]], p = tr[p][1];
|
|
|
|
|
//(1) res += (1 << i) //恢复原始数据的拼接过程
|
|
|
|
|
//(2) x -= cnt[tr[p][0]] 减去左手边的个数
|
|
|
|
|
//(3) p = tr[p][1] 向右手边继续游标前进
|
|
|
|
|
else
|
|
|
|
|
p = tr[p][0]; //游标p向左移动进去,继续前行
|
|
|
|
|
}
|
|
|
|
|
return res - base; //因为我们之前加过一个base,所以这里要减去
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main() {
|
|
|
|
|
int n;
|
|
|
|
|
scanf("%d", &n);
|
|
|
|
|
while (n--) {
|
|
|
|
|
int op, x;
|
|
|
|
|
scanf("%d%d", &op, &x);
|
|
|
|
|
if (op == 1) insert(x, 1); //插入x
|
|
|
|
|
if (op == 2) insert(x, -1); //删除x
|
|
|
|
|
if (op == 3) cout << rnk(x) + 1 << endl; //查询严格小于x的个数,再+1,就是x的排名
|
|
|
|
|
if (op == 4) cout << find_kth(x) << endl; //查询第k位置的数
|
|
|
|
|
if (op == 5) cout << find_kth(rnk(x)) << endl; // x的前驱(小于x的最大值)
|
|
|
|
|
if (op == 6) cout << find_kth(rnk(x + 1) + 1) << endl; // x的后继(大于x的最小值)
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|