题意(以 P2710 为例)
思路
使用 FHQ-Treap 进行求解,清晰明了。
- 对于 insert,先将要插入的数建成一棵树,然后将这棵树放入 FHQ-Treap 中。
- 对于 delete,将要删除的树分离出来,然后把剩下的部分合并即可,将删除的树的树根丢到废弃节点的栈中以备以后使用(节约空间,不然 MLE)。
- 对于 reverse,给一个节点打上标签并立即交换,参考文艺平衡树代码。注意,如果存在
MAKE-SAME
操作的标签,那么不用反转,因为所有数字都是一样的。 - 对于 make-same,将这个节点的 reverse 的标记清空(用不到,理由如上),给这个节点打上标记并立即更新结构体中所有数字。
- 对于 get-sum,pushup 维护即可。
- 对于 get,与普通平衡树的看排名为 \(x\) 的数字是什么类似。
- 对于 max-sum,最大子段和,参考 GSS-1,注意这是平衡树,对于根节点的处理细节非常多。
代码
细节非常多,注意对废弃节点的处理。(代码以 P2710 为准)
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
const int N = 500010;
const i64 inf = 1e18;
struct node {
int l, r, size, rnd;
int tag_same, tag_rev;
i64 key, lsum, rsum, sum, ans;
} tr[N];
int rt, cnt;
int del_ver[N], top;
int n, m;
int a[N], sz_a;
int newnode(int key) {
int idx;
if (!top) idx = ++cnt;
else {
idx = del_ver[top];
top--;
if (tr[idx].l) del_ver[++top] = (tr[idx].l);
if (tr[idx].r) del_ver[++top] = (tr[idx].r);
}
tr[idx].l = tr[idx].r = 0;
tr[idx].rnd = rand();
tr[idx].size = 1;
tr[idx].tag_same = -1e9;
tr[idx].tag_rev = 0;
tr[idx].key = tr[idx].lsum = tr[idx].rsum = tr[idx].sum = tr[idx].ans = key;
return idx;
}
void addtagrev(int u) {
if (!u) return;
if (tr[u].tag_same != -1e9) return;
tr[u].tag_rev ^= 1;
swap(tr[u].l, tr[u].r);
swap(tr[u].lsum, tr[u].rsum);
}
void addtagsame(int u, int key) {
if (!u) return;
if (tr[u].tag_rev) tr[u].tag_rev = 0;
tr[u].tag_same = tr[u].key = key;
tr[u].sum = key * tr[u].size;
tr[u].lsum = tr[u].rsum = tr[u].ans = max(tr[u].key, tr[u].sum);
}
void pushdown(int u) {
if (tr[u].tag_same != -1e9) {
tr[u].tag_rev = 0;
addtagsame(tr[u].l, tr[u].tag_same);
addtagsame(tr[u].r, tr[u].tag_same);
tr[u].tag_same = -1e9;
}
if (tr[u].tag_rev) {
addtagrev(tr[u].l);
addtagrev(tr[u].r);
tr[u].tag_rev = 0;
}
}
void pushup(int u) {
tr[u].size = tr[tr[u].l].size + tr[tr[u].r].size + 1;
tr[u].lsum = max({tr[tr[u].l].lsum, tr[tr[u].l].sum + tr[u].key, tr[tr[u].l].sum + tr[tr[u].r].lsum + tr[u].key});
tr[u].rsum = max({tr[tr[u].r].rsum, tr[tr[u].r].sum + tr[u].key, tr[tr[u].r].sum + tr[tr[u].l].rsum + tr[u].key});
tr[u].sum = tr[tr[u].l].sum + tr[tr[u].r].sum + tr[u].key;
tr[u].ans = max({tr[tr[u].l].ans, tr[tr[u].r].ans, tr[u].key, tr[tr[u].l].rsum + tr[u].key, tr[tr[u].r].lsum + tr[u].key, tr[tr[u].l].rsum + tr[u].key + tr[tr[u].r].lsum});
}
void split(int u, int sz, int &x, int &y) {
if (!u) {
x = y = 0;
return;
}
pushdown(u);
if (tr[tr[u].l].size + 1 <= sz) {
x = u;
split(tr[u].r, sz - tr[tr[u].l].size - 1, tr[u].r, y);
}
else {
y = u;
split(tr[u].l, sz, x, tr[u].l);
}
pushup(u);
}
int merge(int x, int y) {
if ((!x) || (!y)) return x | y;
if (tr[x].rnd < tr[y].rnd) {
pushdown(x);
tr[x].r = merge(tr[x].r, y);
pushup(x);
return x;
}
else {
pushdown(y);
tr[y].l = merge(x, tr[y].l);
pushup(y);
return y;
}
}
void del(int l, int r) {
int x, y, z;
split(rt, r, x, z);
split(x, l - 1, x, y);
del_ver[++top] = (y);
rt = merge(x, z);
}
int build(int l, int r) {
if (l == r) return newnode(a[l]);
int mid = (l + r) >> 1;
int x = build(l, mid);
int y = build(mid + 1, r);
return merge(x, y);
}
void insert(int p) {
int x, y;
int rt2 = build(1, sz_a);
split(rt, p, x, y);
rt = merge(merge(x, rt2), y);
}
void make_same(int l, int r, int c) {
int x, y, z;
split(rt, r, x, z);
split(x, l - 1, x, y);
addtagsame(y, c);
rt = merge(merge(x, y), z);
}
void reverse_arr(int l, int r) {
int x, y, z;
split(rt, r, x, z);
split(x, l - 1, x, y);
addtagrev(y);
rt = merge(merge(x, y), z);
}
i64 get_sum(int l, int r) {
int x, y, z;
split(rt, r, x, z);
split(x, l - 1, x, y);
i64 ans = tr[y].sum;
rt = merge(merge(x, y), z);
return ans;
}
i64 get_max(int l, int r) {
int x, y, z;
split(rt, r, x, z);
split(x, l - 1, x, y);
i64 ans = tr[y].ans;
rt = merge(merge(x, y), z);
return ans;
}
int get_num(int u, int rk) {
pushdown(u);
if (tr[tr[u].l].size + 1 == rk) return tr[u].key;
else if (tr[tr[u].l].size >= rk) return get_num(tr[u].l, rk);
else return get_num(tr[u].r, rk - tr[tr[u].l].size - 1);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
tr[0].lsum = tr[0].rsum = tr[0].ans = -inf;
for (int i = 1; i <= n; i++) cin >> a[i];
sz_a = n;
insert(0);
string opt;
int x, y, z;
for (int T = 1; T <= m; T++) {
cin >> opt;
if (opt == "INSERT") {
cin >> x >> sz_a;
for (int i = 1; i <= sz_a; i++) cin >> a[i];
insert(x);
}
else if (opt == "DELETE") {
cin >> x >> y;
del(x, x + y - 1);
}
else if (opt == "MAKE-SAME") {
cin >> x >> y >> z;
make_same(x, x + y - 1, z);
}
else if (opt == "REVERSE") {
cin >> x >> y;
reverse_arr(x, x + y - 1);
}
else if (opt == "GET-SUM") {
cin >> x >> y;
cout << get_sum(x, x + y - 1) << '\n';
}
else if (opt == "GET") {
cin >> x;
cout << get_num(rt, x) << '\n';
}
else {
cin >> x >> y;
cout << get_max(x, x + y - 1) << '\n';
}
}
return 0;
}
标签:数列,idx,int,sum,tr,NOI2005,P2710,key,tag
From: https://www.cnblogs.com/Yuan-Jiawei/p/18419323