【luogu P3369】普通平衡树(fhq Treap 做法)
普通平衡树
题目链接:luogu P3369
题目大意
平衡树模板题,要求维护一些操作。 插入一个数,删除一个数,查询一个数的排名,查询排名一直的数,找前驱后继。
思路
这次我们用 fhq Treap(无旋 Treap)来做。
无旋 Treap 就是搞把树分裂与合并来实现对堆和二叉排序树的维护。
然后这里讲一下一些操作的实现。
插入输出很好想,两种排名也好搞。
而找前驱可以先按这个数割树,这个数放在右边,然后左边的树一直往右走。
而找后继可以先按这个数 \(+1\) 个数,使得这个数放在左边的最右边,然后右边的树一直往左走。
具体实现可以看看代码。
代码
#include<queue>
#include<cstdio>
#include<cstdlib>
using namespace std;
int ls[100001], rs[100001], val[100001], yj[100001], sz[100001], sum[100001];
int n, op, x, tot, root;
int make_new(int num) {
int now = ++tot;
sz[now] = 1;
ls[now] = rs[now] = 0;
val[now] = num;
yj[now] = rand();
return now;
}
void up(int now) {
sz[now] = sz[ls[now]] + sz[rs[now]] + 1;
}
pair <int, int> split_rnk(int now, int rnk) {
if (!now) return make_pair(0, 0);
if (!rnk) return make_pair(0, now);
pair <int, int> re;
if (sz[ls[now]] >= rnk) {
re = split_rnk(ls[now], rnk);
ls[now] = re.second;
up(now);
re.second = now;
}
else {
re = split_rnk(rs[now], rnk - sz[ls[now]] - 1);
rs[now] = re.first;
up(now);
re.first = now;
}
return re;
}
pair <int, int> split_val(int now, int num) {
if (!now) return make_pair(0, 0);
pair <int, int> re;
if (num <= val[now]) {
re = split_val(ls[now], num);
ls[now] = re.second;
up(now);
re.second = now;
}
else {
re = split_val(rs[now], num);
rs[now] = re.first;
up(now);
re.first = now;
}
return re;
}
int merge(int x, int y) {
if (!x) return y;
if (!y) return x;
if (yj[x] < yj[y]) {
rs[x] = merge(rs[x], y);
up(x);
return x;
}
else {
ls[y] = merge(x, ls[y]);
up(y);
return y;
}
}
void insert(int x) {
int now = make_new(x);
pair <int, int> y = split_val(root, x);
root = merge(merge(y.first, now), y.second);
}
void delete_(int now) {
pair <int, int> x = split_val(root, now);
pair <int, int> y = split_rnk(x.second, 1);
root = merge(x.first, y.second);
}
int ask_rnk(int now) {
pair <int, int> x = split_val(root, now);
int re = sz[x.first] + 1;
root = merge(x.first, x.second);
return re;
}
int ask_val(int now) {
pair <int, int> x = split_rnk(root, now - 1);
pair <int, int> y = split_rnk(x.second, 1);
int re = val[y.first];
root = merge(x.first, merge(y.first, y.second));
return re;
}
int get_pre(int now) {
pair <int, int> x = split_val(root, now);
int X = x.first, Y = 0;
while (X) {
Y = X;
X = rs[X];
}
root = merge(x.first, x.second);
return val[Y];
}
int get_nxt(int now) {
pair <int, int> x = split_val(root, now + 1);
int X = x.second, Y = 0;
while (X) {
Y = X;
X = ls[X];
}
root = merge(x.first, x.second);
return val[Y];
}
int main() {
srand(1919810);
scanf("%d", &n);
while (n--) {
scanf("%d %d", &op, &x);
if (op == 1) {
insert(x);
continue;
}
if (op == 2) {
delete_(x);
continue;
}
if (op == 3) {
printf("%d\n", ask_rnk(x));
continue;
}
if (op == 4) {
printf("%d\n", ask_val(x));
continue;
}
if (op == 5) {
printf("%d\n", get_pre(x));
continue;
}
if (op == 6) {
printf("%d\n", get_nxt(x));
continue;
}
}
return 0;
}