题目大意:需要提供以下操作:
- 插入 $x$ 数
- 删除 $x$ 数(若有多个相同的数,应只删除一个)
- 查询 $x$ 数的排名(排名定义为比当前数小的数的个数 $+1$ 。若有多个相同的数,因输出最小的排名)
- 查询排名为 $x$ 的数
- 求 $x$ 的前驱(前驱定义为小于 $x$ ,且最大的数)
- 求 $x$ 的后继(后继定义为大于 $x$ ,且最小的数)
题解:平衡树,treap
卡点:无
C++ Code:
#include <cstdio>
#include <cstdlib>
#define maxn 100050
using namespace std;
int n, op, x;
struct treap {
int lc[maxn], rc[maxn], val[maxn], num[maxn], sz[maxn]; //val值,num堆值
int root, idx;
int ta, tb, tmp, res;
int update(int p) {
sz[p] = sz[lc[p]] + sz[rc[p]] + 1;
return p;
}
int nw(int p) {
val[++idx] = p;
sz[idx] = 1;
num[idx] = rand();
return idx;
}
void split(int rt, int k, int &x, int &y) {
if (!rt) x = y = 0;
else {
if (val[rt] <= k) split(rc[rt], k, rc[rt], y), x = update(rt);
else split(lc[rt], k, x, lc[rt]), y = update(rt);
}
}
int merge(int x, int y) {
if (!x || !y) return x|y;
if (num[x] > num[y]) {rc[x] = merge(rc[x], y); return update(x);}
else {lc[y] = merge(x, lc[y]); return update(y);}
}
void insert(int p) {
if (!root) {
root = nw(p);
} else {
split(root, p, ta, tb);
root = merge(merge(ta, nw(p)), tb);
}
}
void erase(int p) {
split(root, p, ta, tb);
split(ta, p - 1, ta, tmp);
root = merge(ta, merge(merge(lc[tmp], rc[tmp]), tb));
}
int gtrnk(int p) {
split(root, p - 1, ta, tb);
res = sz[ta] + 1;
root = merge(ta, tb);
return res;
}
int gtk_th(int p, int k) {
while (true) {
if (sz[lc[p]] >= k) p = lc[p];
else
if (sz[lc[p]] + 1 == k) return val[p];
else k -= sz[lc[p]] + 1, p = rc[p];
}
}
int pre(int p) {
split(root, p - 1, ta, tb);
res = gtk_th(ta, sz[ta]);
root = merge(ta, tb);
return res;
}
int nxt(int p) {
split(root, p, ta, tb);
res = gtk_th(tb, 1);
root = merge(ta, tb);
return res;
}
} T;
int main() {
srand(20040826);
scanf("%d", &n);
while (n--) {
scanf("%d%d", &op, &x);
switch (op) {
case 1: {
T.insert(x);
break;
}
case 2: {
T.erase(x);
break;
}
case 3: {
printf("%d\n", T.gtrnk(x));
break;
}
case 4: {
printf("%d\n", T.gtk_th(T.root, x));
break;
}
case 5: {
printf("%d\n", T.pre(x));
break;
}
case 6: {
printf("%d\n", T.nxt(x));
break;
}
}
}
return 0;
}