#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
const int INF = 0x3f3f3f3f;
inline int read() {
char ch = getchar(); int flag = 1, ans = 0;
while (ch < '0' || ch > '9') { if (ch == '-') flag = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { ans = (ans << 1) + (ans << 3) + ch - '0'; ch = getchar(); }
return flag * ans;
}
struct Node {
Node* ch[2]; // 两个子节点的地址
int val, rank;
int rep_cnt; // val出现的次数
int siz; // 子树点数
Node (int v) : val(v), rep_cnt(1), siz(1) {
ch[0] = ch[1] = nullptr;
rank = rand();
}
void upd_siz() {
// 用于旋转和删除过后, 重新计算siz的值
siz = rep_cnt;
if (ch[0] != nullptr) siz += ch[0]->siz;
if (ch[1] != nullptr) siz += ch[1]->siz;
}
};
class Treap {
private:
Node* root;
/* 旋转, 0为左旋, 1为右旋 单旋只需考虑两个旋转节点的左右子树及父亲*/
void _rotate(Node*& cur, int dir) {
Node* tmp = cur->ch[!dir]; // tmp临时指向新根(方便)
cur->ch[!dir] = tmp->ch[dir]; // cur未来的右/左子树为其左/右的右/左子树
tmp->ch[dir] = cur;
cur->upd_siz(), tmp->upd_siz(); // 更新大小信息
cur = tmp;
}
// 树上操作皆使用分治思想解决
// 插入
void _insert(Node*& cur, int val) {
if (cur == nullptr) {
cur = new Node(val);
return;
}
if (val == cur->val) {
cur->rep_cnt++;
cur->siz++;
return;
}
if (val < cur->val) {
_insert(cur->ch[0], val);
if (cur->ch[0]->rank < cur->rank) _rotate(cur, 1);
cur->upd_siz(); // 大小变化, 需要更新 (注意_rotate的更新不能替代这次)
} else {
_insert(cur->ch[1], val);
if (cur->ch[1]->rank < cur->rank) _rotate(cur, 0);
cur->upd_siz();
}
}
// 删除, 需分类讨论
void _del(Node*& cur, int val) {
if (val < cur->val) {
_del(cur->ch[0], val);
cur->upd_siz();
} else if (val > cur->val) {
_del(cur->ch[1], val);
cur->upd_siz();
} else {
if (cur->rep_cnt > 1) {
cur->rep_cnt--, cur->siz--;
return;
}
int state = 0;
state |= (cur->ch[0] != nullptr);
state |= ((cur->ch[1] != nullptr) << 1);
// 位0为是否有左子树, 位1为是否有右子树
Node* tmp = cur;
if (state == 0) {
delete cur;
cur = nullptr;
} else if (state == 1) {
cur = tmp->ch[0];
delete tmp;
} else if (state == 2) {
cur = tmp->ch[1];
delete tmp;
} else {
int dir = cur->ch[0]->rank < cur->ch[1]->rank ? 1 : 0;
// 若左边rank小就右旋将左儿子提上去, 右边同理
_rotate(cur, dir);
_del(cur->ch[dir], val);
cur->upd_siz();
}
}
}
// 根据值查询排名
int _query_rank(Node* cur, int val) {
int lc_siz = cur->ch[0] == nullptr ? 0 : cur->ch[0]->siz;
// 这个树中小于val的节点的数量
if (val == cur->val) return lc_siz + 1; // 若该节点为目标
else if (val < cur->val) {
if (cur->ch[0] != nullptr)
return _query_rank(cur->ch[0], val);
else return 1; // 如果左子树是空的, 返回小于val的数的个数+1, 即将val插入后的位置
} else {
if (cur->ch[1] != nullptr)
return lc_siz + cur->rep_cnt + _query_rank(cur->ch[1], val);
else return cur->siz + 1; // 相当于lc_siz + cur->rep_cnt + 1
}
}
// 根据排名查询值
int _query_val(Node* cur, int rank) {
if (cur == nullptr) return -INF;
int lc_siz = cur->ch[0] == nullptr ? 0 : cur->ch[0]->siz;
// 左子树大小
if (rank <= lc_siz)
return _query_val(cur->ch[0], rank);
else if (rank <= lc_siz + cur->rep_cnt)
return cur->val;
else
return _query_val(cur->ch[1], rank - lc_siz - cur->rep_cnt);
}
// 查询第一个比val小的节点, 可转换为找第一个<=val-1的值
int _query_prev(Node* cur, int val) {
// if (cur == nullptr) return -INF;
if (cur->val == val - 1) return cur->val;
if (val - 1 < cur->val)
return _query_prev(cur->ch[0], val);
if (val - 1 > cur->val)
if (cur->ch[1] == nullptr) return cur->val;
else return _query_prev(cur->ch[1], val);
}
// 查询第一个比val大的节点, 可转换为找第一个>=val+1的值
int _query_next(Node* cur, int val) {
// if (cur == nullptr) return -INF;
if (cur->val == val + 1) return cur->val;
if (val + 1 > cur->val)
return _query_next(cur->ch[1], val);
if (val + 1 < cur->val)
if (cur->ch[0] == nullptr) return cur->val;
else return _query_next(cur->ch[0], val);
}
public:
void insert(int val) { _insert(root, val); }
void del(int val) { _del(root, val); }
int query_rank(int val) { return _query_rank(root, val); }
int query_val(int val) { return _query_val(root, val); }
int query_prev(int val) { return _query_prev(root, val); }
int query_next(int val) { return _query_next(root, val); }
};
Treap tr;
int main() {
// freopen("a.in", "r", stdin);
// freopen("a.out", "w", stdout);
srand(0);
int n = read();
while (n--) {
int opt = read(), x = read();
if (opt == 1) tr.insert(x);
else if (opt == 2) tr.del(x);
else if (opt == 3) printf("%d\n", tr.query_rank(x));
else if (opt == 4) printf("%d\n", tr.query_val(x));
else if (opt == 5) printf("%d\n", tr.query_prev(x));
else printf("%d\n", tr.query_next(x));
}
// system("pause");
// fclose(stdin);
// fclose(stdout);
return 0;
}
第一个点(即样例)就RE了,但本地测试没有问题,求dalao指点