题目大意:
来维护一些数,其中需要提供以下操作(对于各个以往的历史版本):
-
插入x数
-
删除x数(若有多个相同的数,因只删除一个,如果没有请忽略该操作)
-
查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)
-
查询排名为x的数
-
求x的前驱(前驱定义为小于x,且最大的数,如不存在输出-2147483647)
-
求x的后继(后继定义为大于x,且最小的数,如不存在输出2147483647)
和原本平衡树不同的一点是,每一次的任何操作都是基于某一个历史版本,同时生成一个新的版本。(操作3, 4, 5, 6即保持原版本无变化)
每个版本的编号即为操作的序号(版本0即为初始状态,空树)
题解:可持久化平衡树,就是在merge和split的时候不修改原来的点,改为新增一个点存放
卡点:1.未考虑第一次插入因为树中没有节点,与其他的不同,需要特殊考虑,而导致后面出错
C++ Code:
#include <cstdio>
#include <cstdlib>
#define maxn 500010
using namespace std;
const int inf = 2147483647;
int n, ver, op, x;
int root[maxn];
struct Tree {
int lc[maxn * 50], rc[maxn * 50], val[maxn * 50], num[maxn * 50], sz[maxn * 50]; //val值,num堆值
int idx, ta, tb, tmp, res;
void debug(int p) {
if (lc[p]) debug(lc[p]);
printf("%d : val %d lc %d rc %d\n", p, val[p], lc[p], rc[p]);
if (rc[p]) debug(rc[p]);
}
void cpy(int cur, int ver) {
lc[cur] = lc[ver];
rc[cur] = rc[ver];
val[cur] = val[ver];
num[cur] = num[ver];
sz[cur] = sz[ver];
}
void update(int rt) {sz[rt] = sz[lc[rt]] + sz[rc[rt]] + 1;}
int nw(int p) {
val[++idx] = p;
sz[idx] = 1;
num[idx] = rand();
return idx;
}
void split(int rt, int p, int &x, int &y) {
if (!rt) x = y = 0;
else {
if (val[rt] <= p) {
x = ++idx;
cpy(x, rt);
split(rc[x], p, rc[x], y);
update(x);
} else {
y = ++idx;
cpy(y, rt);
split(lc[y], p, x, lc[y]);
update(y);
}
}
}
int merge(int x, int y) {
if (!x || !y) return x | y;
int o;
if (num[x] < num[y]) {
o = ++idx;
cpy(o, x);
rc[o] = merge(rc[o], y);
} else {
o = ++idx;
cpy(o, y);
lc[o] = merge(x, lc[o]);
}
update(o);
return o;
}
void insert(int &rt, int x) {
if (!rt) rt = nw(x);
else {
split(rt, x, ta, tb);
// printf("Debug:%d %d\n", ta, tb);
rt = merge(merge(ta, nw(x)), tb);
}
}
void erase(int &rt, int x) {
split(rt, x, ta, tb);
split(ta, x - 1, ta, tmp);
// printf("%d %d %d\n", ta, tb, tmp);
if (val[tmp] != x) rt = merge(merge(ta, tmp), tb);
else rt = merge(merge(ta, merge(lc[tmp], rc[tmp])), tb);
}
int gtrnk(int rt, int x) {
split(rt, x - 1, ta, tb);
res = sz[ta] + 1;
merge(ta, tb);
return res;
}
int gtkth(int rt, int k) {
while (true) {
if (k <= sz[lc[rt]]) rt = lc[rt];
else {
if (k == sz[lc[rt]] + 1) return val[rt];
else k -= sz[lc[rt]] + 1, rt = rc[rt];
}
}
}
int pre(int rt, int x) {
split(rt, x - 1, ta, tb);
if (!ta) res = -inf;
else res = gtkth(ta, sz[ta]), merge(ta, tb);
return res;
}
int nxt(int rt, int x) {
split(rt, x, ta, tb);
if (!tb) res = inf;
else res = gtkth(tb, 1), merge(ta, tb);
return res;
}
} T;
int main() {
srand(20040826);
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d%d%d", &ver, &op, &x);
root[i] = root[ver];
switch (op) {
case 1: {
T.insert(root[i], x);
// T.debug(root[i]);
break;
}
case 2: {
T.erase(root[i], x);
// T.debug(root[i]);
break;
}
case 3: {
printf("%d\n", T.gtrnk(root[i], x));
// T.debug(root[i]);
break;
}
case 4: {
printf("%d\n", T.gtkth(root[i], x));
// T.debug(root[i]);
break;
}
case 5: {
printf("%d\n", T.pre(root[i], x));
// T.debug(root[i]);
break;
}
case 6: {
printf("%d\n", T.nxt(root[i], x));
// T.debug(root[i]);
break;
}
}
}
return 0;
}