Splay学的头痛,还不知道要怎么用
还是学一学无旋Treap养老比较好,splay能写的也能写,但是常数比较大
依赖随机化大法,复杂度还是比较优秀
主要依靠split分裂操作和merge合并操作来实现各种操作
推荐视频:https://www.bilibili.com/video/av60140850?from=search&seid=2025355617102903408
#include <bits/stdc++.h>
using namespace std;
const int nmax = 1e6 + 7;
const int INF = 0x3f3f3f3f;
struct node {
int val, rnk, lc, rc, size;
} tree[nmax];
int tot, seed = 233, root = 0;
inline int rrand() {
return seed = int(seed * 482711ll % 2147483647);
}
inline void update(int rt) {
tree[rt].size = tree[tree[rt].lc].size + tree[tree[rt].rc].size + 1;
}
int add_node(int val) {
tree[++tot].size = 1;
tree[tot].val = val;
tree[tot].lc = tree[tot].rc = 0;
tree[tot].rnk = rrand();
return tot;
}
void split(int rt, int & a, int & b, int val) {
//a <= val, b > val按值分裂
if (rt == 0) {
a = b = 0;
return;
}
if (tree[rt].val <= val) {
a = rt;
split(tree[rt].rc, tree[a].rc, b, val);
} else {
b = rt;
split(tree[rt].lc, a, tree[b].lc, val);
}
update(rt);
}
void split(int rt, int &a, int &b, int k) {
//分裂成两个子树,其中左子树大小等于k
if (rt == 0) {
a = b = 0;
return;
}
int c = tree[tree[rt].lc].size;
if (c < k) {
a = rt;
split(tree[rt].rc, tree[rt].rc, b, k - c - 1);
}
else {
b = rt;
split(tree[rt].lc, a, tree[rt].lc, k);
}
update(rt);
}
void merge(int & rt, int a, int b) {
// 前提:a的权值全部 < b的权值
if (a == 0 || b == 0) {
rt = a + b;
return;
}
if (tree[a].rnk < tree[b].rnk) {
rt = a;
merge(tree[rt].rc, tree[a].rc, b);
} else {
rt = b;
merge(tree[rt].lc, a, tree[b].lc);
}
update(rt);
}
void insert(int & rt, int val) {
// 插入一个值为val的节点
int x = 0, y = 0, nnode = add_node(val);
split(rt, x, y, val);
merge(x, x, nnode);
merge(rt, x, y);
}
void delete_node(int & rt, int val) {
// 删除值为val的节点
int x = 0, y = 0, z = 0;
split(rt, x, y, val);
split(x, x, z, val - 1);
merge(z, tree[z].lc, tree[z].rc);
merge(x, x, z);
merge(rt, x, y);
}
int get_kth(int rt, int k) {
// 找第k大的数值
while (tree[tree[rt].lc].size + 1 != k) {
if (tree[tree[rt].lc].size >= k)
rt = tree[rt].lc;
else {
k -= tree[tree[rt].lc].size + 1;
rt = tree[rt].rc;
}
}
return tree[rt].val;
}
int get_rank(int & rt, int val) {
// 查找值对应第几大
int x = 0, y = 0;
split(rt, x, y, val - 1);
int tmp = tree[x].size + 1;
merge(rt, x, y);
return tmp;
}
int get_pre(int & rt, int val) {
// 找值为val的前驱节点数值
int x = 0, y = 0;
split(rt, x, y, val - 1);
int tmp = get_kth(x, tree[x].size);
merge(rt, x, y);
return tmp;
}
int get_scc(int & rt, int val) {
// 找值为val的后继节点数值
int x = 0, y = 0;
split(rt, x, y ,val);
int tmp = get_kth(y, 1);
merge(rt, x, y);
return tmp;
}
int n;
int main() {
scanf("%d", &n);
int op, val;
add_node(INF);
tot = 1;
tree[1].size = 0;
root = 1;
for (int i = 1; i <= n; ++i) {
scanf("%d %d", &op, &val);
if (op == 1) {
insert(root, val);
} else if (op == 2) {
delete_node(root, val);
} else if (op == 3) {
printf("%d\n", get_rank(root, val));
} else if (op == 4) {
printf("%d\n", get_kth(root, val));
} else if (op == 5) {
printf("%d\n", get_pre(root, val));
} else {
printf("%d\n", get_scc(root, val));
}
}
return 0;
}
例题:https://www.luogu.org/problem/P3391
每次翻转l-r区间内容,需要给结点打上懒标记,在split和merge里需要子树信息之前就需要pushdown
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
struct fhq_Treap
{
struct node
{
int val, rnk, lc, rc, sz;
bool lzy;
} t[maxn];
int tot = 0, seed = 233, root = 0;
inline int rrand() {
return seed = int(seed * 482711ll % 2147483647);
}
inline void pushup(int rt) {
t[rt].sz = t[t[rt].lc].sz + t[t[rt].rc].sz + 1;
}
inline void pushdown(int rt) {
if (rt && t[rt].lzy) {
swap(t[rt].lc, t[rt].rc);
t[rt].lzy = false;
t[t[rt].lc].lzy ^= 1;
t[t[rt].rc].lzy ^= 1;
}
}
int add_node(int val) {
t[++tot].sz = 1;
t[tot].val = val;
t[tot].lc = t[tot].rc = 0;
t[tot].rnk = rrand();
t[tot].lzy = false;
return tot;
}
void split(int rt, int &a, int &b, int k) {
//分裂成两个子树,其中左子树大小等于k
if (rt == 0) {
a = b = 0;
return;
}
pushdown(rt);
int c = t[t[rt].lc].sz;
if (c < k) {
a = rt;
split(t[rt].rc, t[rt].rc, b, k - c - 1);
}
else {
b = rt;
split(t[rt].lc, a, t[rt].lc, k);
}
pushup(rt);
}
void merge(int & rt, int a, int b) {
// 前提:a的权值全部 < b的权值
if (a == 0 || b == 0) {
rt = a + b;
return;
}
if (t[a].rnk < t[b].rnk) {
rt = a; pushdown(rt);
merge(t[rt].rc, t[a].rc, b);
} else {
rt = b; pushdown(rt);
merge(t[rt].lc, a, t[b].lc);
}
pushup(rt);
}
void reverse(int l, int r) {
int x = 0, y = 0, z = 0;
split(root, x, y, l - 1);
split(y, y, z, r - l + 1);
t[y].lzy ^= 1;
merge(y, x, y);
merge(root, y, z);
}
bool output_flg = true;
void output(int rt) {
if (!rt) return;
pushdown(rt);
output(t[rt].lc);
if (output_flg) output_flg = false, printf("%d", t[rt].val);
else printf(" %d", t[rt].val);
output(t[rt].rc);
}
} tep;
int main()
{
freopen("in.txt", "r", stdin);
int n, m; scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) {
tep.merge(tep.root, tep.root, tep.add_node(i));
}
while (m--) {
int l, r; scanf("%d%d", &l, &r);
tep.reverse(l, r);
}
tep.output(tep.root);
putchar('\n');
}