题目链接
题意
您需要写一种数据结构(可参考题目标题),来维护一个可重整数集合,其中需要提供以下操作,(对于各个以往的历史版本):
case 1: 插入
x
x
x数
case 2: 删除
x
x
x数(若有多个相同的数,因只删除一个)
case 3: 查询
x
x
x数的排名(排名定义为比当前数小的数的个数
+
1
+1
+1)
case 4: 查询排名为
x
x
x的数
case 5: 求
x
x
x的前驱(前驱定义为小于
x
x
x,且最大的数,如不存在输出
−
2
31
+
1
-2^{31}+1
−231+1)
case 6: 求
x
x
x的后继(后继定义为大于
x
x
x,且最小的数,不存在输出
2
31
−
1
2^{31}-1
231−1)
和原本平衡树不同的一点是,每一次的任何操作都是基于某一个历史版本,同时生成一个新的版本。(操作3, 4, 5, 6即保持原版本无变化)
每个版本的编号即为操作的序号(版本0即为初始状态,空树)
思路
笔者是用这个思路过了的
在这里我们需要用到多个根
和可持续化线段树一样
每一次操作我们建一段新树
然后把根保存起来
注意事项
数组大小开50
倍
笔者亲测50倍能过, RE了好几次
(求互关)
根单独存放
第一次操作的根是0
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <cctype>
#include <map>
#include <set>
#include <vector>
#include <iostream>
#include <cmath>
#define pk putchar(' ')
#define ph puts("")
#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
template <class T>
void rd(T &x)
{
x = 0;
int f = 1;
char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
x *= f;
}
template <class T>
void pt(T x)
{
if (x < 0)
putchar('-'), x = (~x) + 1;
if (x > 9)
pt(x / 10);
putchar(x % 10 ^ 48);
}
template <class T>
T Max(T a, T b)
{
return a > b ? a : b;
}
template <class T>
T Min(T a, T b)
{
return a < b ? a : b;
}
using namespace std;
const int INF = 0x3f3f3f3f, N = 5e5 + 5;
int n, rt[N];
struct Node
{
int val, rnd, siz, l ,r;
};
struct Treapnode
{
Node t[N * 50];
int tot;
void New(int &p, int x)
{
p = ++tot;
t[p].val = x;
t[p].siz = 1;
t[p].rnd = rand();
}
void update(int p)
{
t[p].siz = t[t[p].l].siz + t[t[p].r].siz + 1;
}
// 更新
int merge(int a,int b)
{
if (!a || !b)
return a + b;
if (t[a].rnd > t[b].rnd)
{
int p = ++tot;
t[p] = t[a];
t[p].r = merge(t[p].r, b);
update(p);
return p;
}
else
{
int p = ++tot;
t[p] = t[b];
t[p].l = merge(a, t[p].l);
update(p);
return p;
}
}
// 合并
void split(int p, int k, int& x, int& y)
{
if (!p)
return (void)(x = y = 0);
if (t[p].val <= k)
{
x = ++tot;
t[x] = t[p];
split(t[x].r, k, t[x].r, y);
update(x);
}
else
{
y = ++tot;
t[y] = t[p];
split(t[y].l, k, x, t[y].l);
update(y);
}
}
// 按权值大小拆分
void ins(int& p, int x)
{
int a = 0, b = 0, c = 0;
split(p, x, a, b);
New(c, x);
p = merge(merge(a, c), b);
}
// 插入x
void del(int& p, int x)
{
int a = 0, b = 0, c = 0;
split(p, x, a, c);
split(a, x - 1, a, b);
b = merge(t[b].l, t[b].r);
p = merge(merge(a, b), c);
}
// 删除x
int get_rank(int& p, int x)
{
int a, b, c;
split(p, x - 1, a, b);
c = t[a].siz + 1;
p = merge(a, b);
return c;
}
int get_val(int p, int x)
{
if (x == t[t[p].l].siz + 1)
return t[p].val;
else if (x <= t[t[p].l].siz)
return get_val(t[p].l, x);
else
return get_val(t[p].r, x - t[t[p].l].siz - 1);
}
// 找第x的值
int pre(int& p, int x)
{
int a, b, c;
split(p, x - 1, a, b);
if (!a)
return -2147483647;
c = get_val(a, t[a].siz);
p = merge(a, b);
return c;
}
// 找前驱
int sub(int& p, int x)
{
int a, b, c;
split(p, x, a, b);
if (!b)
return 2147483647;
c = get_val(b, 1);
p = merge(a, b);
return c;
}
// 找后缀
}Treap;
int main()
{
// freopen("testdata.in", "r", stdin);
// freopen("test.out", "w", stdout);
rd(n);
int tim, opt, x;
for (int i = 1;i <= n; i++)
{
rd(tim), rd(opt), rd(x);
rt[i] = rt[tim];
switch(opt)
{
case 1: Treap.ins(rt[i], x); break;
case 2: Treap.del(rt[i], x); break;
case 3: pt(Treap.get_rank(rt[i], x)), ph; break;
case 4: pt(Treap.get_val(rt[i], x)), ph; break;
case 5: pt(Treap.pre(rt[i], x)), ph; break;
case 6: pt(Treap.sub(rt[i], x)), ph; break;
}
}
return 0;
}