[洛谷P3835]【模板】可持久化平衡树
题目大意:
来维护一些数,其中需要提供以下操作(对于各个以往的历史版本):
-
插入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; }