FHQ-Treap学习笔记
FHQ-Treap可以解决的问题:splay能解决的除了LCT以外的所有问题。
FHQ-Treap有两种操作,分别是merge和split。
FHQ-Treap和普通的Treap一样,都有两个值key和val。
mt19937 gen(chrono::system_clock::now().time_since_epoch().count());
uniform_int_distribution <int> rnd;
void initmtrft(int mvfzgh = 100000000) {
uniform_int_distribution <int> rndtmpfimt(1, mvfzgh);
rnd = rndtmpfimt;
}
int grfntrft() {
return rnd(gen);
}
struct Node {
int val, key, size;
int l, r;
Node () {
val = 0;
size = l = r = 0;
key = grfntrft();
}
}
merge操作:合并两棵FHQ-Treap。类似于启发式合并,在两棵Treap中找到根节点key值最大的根节点,然后继续递归处理即可。
void merge(int p1, int p2) {
if (!p1)
return p2;
if (!p2)
return p1;
if (z[p1].key > z[p2].key) {
z[p1].r = merge(z[p1].r, p2);
update(p1);
return p1;
} else {
z[p2].l = merge(p1, z[p2].l);
update(p2);
return p2;
}
}
split操作:在一个FHQ-Treap中拆出value最小的 k k k 个节点变成两棵FHQ-Treap。
实际上就是找根操作,如果当前左儿子大小 ≤ k \le k ≤k 那么根在左儿子上,如果 = k + 1 = k+1 =k+1 那么在根节点上(不需特判),如果 > k + 1 >k+1 >k+1 那么根在右儿子上且 k k k 要去掉左儿子和根的值。
pair <int, int> split(int p, int k) {
if (p == 0)
return make_pair(0, 0);
if (z[z[p].l].size + 1 <= k) {
auto res = split(z[p].r, k - z[z[p].l].size - 1);
z[p].r = res.first;
update(p);
return make_pair(p, res.second);
} else {
auto res = split(z[p].l, k);
z[p].l = res.second;
update(p);
return make_pair(res.first, p);
}
}
新建一个空的节点(截自 P2042):
int new_node(int value) {
int p = stk.top();
stk.pop();
z[p].key = rand();
z[p].l = z[p].r = 0;
z[p].size = 1;
z[p].l_max = z[p].r_max = max(0LL, value);
z[p].mx = value;
z[p].value = z[p].sum = value;
z[p].cover = z[p].rever = 0;
z[p].lazy = 0;
return p;
}
例题 洛谷 P2042:
// 代码进行多个优化 请忽视奇怪的Tab长度
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 233;
int n, m;
stack <int> stk;
struct Node {
int key, l, r, value, size, l_max, r_max, sum, cover, rever, mx, lazy;
Node () {
key = l = r = value = size = l_max = r_max = sum = cover = rever = mx = lazy = 0;
}
} z[N];
int rt, a[N];
void init_stk() {
for (int i = 1; i < N - 3; i ++)
stk.push(i);
}
int new_node(int value) {
int p = stk.top();
stk.pop();
z[p].key = rand();
z[p].l = z[p].r = 0;
z[p].size = 1;
z[p].l_max = z[p].r_max = max(0LL, value);
z[p].mx = value; // 题目要求至少选一个
z[p].value = z[p].sum = value;
// * cover 是推平标记
// * rever 是翻转标记
z[p].cover = z[p].rever = 0;
z[p].lazy = 0;
return p;
}
void update(int p) {
z[p].size = z[z[p].l].size + z[z[p].r].size + 1;
z[p].sum = z[z[p].l].sum + z[z[p].r].sum + z[p].value;
z[p].l_max = max(0LL, max(z[z[p].l].l_max, z[z[p].r].l_max + z[z[p].l].sum + z[p].value));
z[p].r_max = max(0LL, max(z[z[p].r].r_max, z[z[p].l].r_max + z[z[p].r].sum + z[p].value));
z[p].mx = max(z[p].value, z[z[p].l].r_max + z[z[p].r].l_max + z[p].value);
if (z[p].l) z[p].mx = max(z[p].mx, z[z[p].l].mx);
if (z[p].r) z[p].mx = max(z[p].mx, z[z[p].r].mx);
}
void reverse(int p) {
swap (z[p].l_max, z[p].r_max);
swap (z[p].l, z[p].r);
z[p].rever ^= 1;
}
void modify(int p, int value) {
z[p].value = z[p].cover = value;
z[p].sum = z[p].size * value;
z[p].l_max = z[p].r_max = max(0LL, z[p].sum);
z[p].mx = max(value, z[p].sum);
z[p].lazy = 1;
}
void pushdown(int p) {
if (z[p].rever) {
if (z[p].l)
reverse(z[p].l);
if (z[p].r)
reverse(z[p].r);
z[p].rever = 0;
}
if (z[p].lazy) {
if (z[p].l)
modify(z[p].l, z[p].cover);
if (z[p].r)
modify(z[p].r, z[p].cover);
z[p].lazy = 0;
}
}
pair <int, int> split(int p, int k) {
if (!p) return make_pair(0, 0);
pushdown(p);
if (z[z[p].l].size >= k) {
auto res = split(z[p].l, k);
z[p].l = res.second;
update(p);
return make_pair(res.first, p);
} else {
auto res = split(z[p].r, k - z[z[p].l].size - 1);
z[p].r = res.first;
update(p);
return make_pair(p, res.second);
}
}
int merge(int a, int b) {
if (!a) return b;
if (!b) return a;
if (z[a].key < z[b].key) {
pushdown(a);
z[a].r = merge(z[a].r, b);
update(a);
return a;
} else {
pushdown(b);
z[b].l = merge(a, z[b].l);
update(b);
return b;
}
}
int build(int l, int r) {
if (l == r)
return new_node(a[l]);
int mid = l + r >> 1;
int res1 = build(l, mid), res2 = build(mid + 1, r);
return merge(res1, res2);
}
void remove(int p) {
stk.push(p);
if (z[p].l)
remove(z[p].l);
if (z[p].r)
remove(z[p].r);
}
void insert(int pos, int tot) {
auto res = split(rt, pos);
rt = merge(merge(res.first, build(1, tot)), res.second);
}
void remove(int pos, int tot) {
auto res = split(rt, pos - 1);
auto res2 = split(res.second, tot);
remove(res2.first);
rt = merge(res.first, res2.second);
}
void reverse(int pos, int tot) {
auto res = split(rt, pos - 1);
auto res2 = split(res.second, tot);
reverse(res2.first);
rt = merge(res.first, merge(res2.first, res2.second));
}
void getsum(int pos, int tot) {
auto res = split(rt, pos - 1);
auto res2 = split(res.second, tot);
cout << z[res2.first].sum << '\n';
rt = merge(res.first, merge(res2.first, res2.second));
}
void modify(int pos, int tot, int value) {
auto res = split(rt, pos - 1);
auto res2 = split(res.second, tot);
modify(res2.first, value);
rt = merge(res.first, merge(res2.first, res2.second));
}
void getmax() {
cout << z[rt].mx << '\n';
}
signed main() {
srand(time(0));
init_stk();
cin >> n >> m;
for (int i = 1; i <= n; i ++)
cin >> a[i];
rt = build(1, n);
while (m --) {
string s;
cin >> s;
if (s == "INSERT") {
int pos, tot;
cin >> pos >> tot;
for (int i = 1; i <= tot; i ++)
cin >> a[i];
insert(pos, tot);
} else if (s == "DELETE") {
int pos, tot;
cin >> pos >> tot;
remove(pos, tot);
} else if (s == "REVERSE") {
int pos, tot;
cin >> pos >> tot;
reverse(pos, tot);
} else if (s == "GET-SUM") {
int pos, tot;
cin >> pos >> tot;
getsum(pos, tot);
} else if (s == "MAX-SUM") {
getmax();
} else {
int pos, tot, value;
cin >> pos >> tot >> value;
modify(pos, tot, value);
}
}
return 0;
}