题目大意:需要提供以下操作:
- 插入 $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 ", T.gtrnk(x)); break; } case 4: { printf("%d ", T.gtk_th(T.root, x)); break; } case 5: { printf("%d ", T.pre(x)); break; } case 6: { printf("%d ", T.nxt(x)); break; } } } return 0; }