先考虑最容易的区间加操作。只要 x\neq 0 那么整个区间的数都变化,所以给 B 作一次区间加即可。
对于区间取最值的操作,你发现你打标记与下传标记是与 B 数组一一对应的。本质上你将序列的数分成三类:最大值、最小值、非最值。并分别维护(只不过你没有建出具体的最值集合而已,但这并不妨碍维护的操作)。因此在打标记的时侯顺便给 B 更新信息即可(注意不是给 B 打标记!是更新信息!)。查询的时侯,你在 A 上查询,下传标记的时侯顺便给 B 更新信息。找到需要的结点后,返回 B 的信息即可。这种操作本质上就是把最值的信息拿给 B 去维护了。另外仍要处理数集的重复问题。
于是我们把这个结点的 Pre 标记拆成 (P_1,P_2)。P_1 表示第一阶段的最大加减标记;P_2 表示第二阶段的最大覆盖标记。利用相似的方法,我们可以对这个做标记下传和信息更新。时间复杂度是 O(m\log n) 的(这个问题并没有区间对 x 取最值的操作哦~)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
char nc() {
static char buf[1000000], *p = buf, *q = buf;
return p == q && (q = (p = buf) + fread(buf, 1, 1000000, stdin), p == q)
? EOF
: *p++;
}
inline ll rd() { // LLONG_MIN LMAX=9,223,372,036,854,775,807
ll s = 0, w = 1;
char ch = nc();
while (ch < '0' || ch > '9') {
if (ch == '-') w = -1;
ch = nc();
}
while (ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = nc();
return s * w;
}
const int N = 1e5 + 7;
struct Tree {
int mx, _mx;
int ad, _ad;
int st, _st;
} g[N * 4];
int a[N];
int n, m;
#define ls u * 2
#define rs u * 2 + 1
#define mid (l + r) / 2
inline void pushup(int u) {
g[u].mx = max(g[ls].mx, g[rs].mx);
g[u]._mx = max(g[ls]._mx, g[rs]._mx);
}
inline void pushadd(int u, int v, int _v) {
g[u]._mx = max(g[u]._mx, g[u].mx + _v), g[u].mx += v;
if (g[u].st == INT_MIN)
g[u]._ad = max(g[u]._ad, g[u].ad + _v), g[u].ad += v;
else
g[u]._st = max(g[u]._st, g[u].st + _v), g[u].st += v;
}
inline void pushset(int u, int v, int _v) {
g[u]._mx = max(g[u]._mx, _v), g[u].mx = v;
g[u]._st = max(g[u]._st, _v), g[u].st = v;
}
inline void pushdown(int u, int l, int r) {
if (g[u].ad)
pushadd(ls, g[u].ad, g[u]._ad), pushadd(rs, g[u].ad, g[u]._ad),
g[u].ad = g[u]._ad = 0;
if (g[u].st != INT_MIN)
pushset(ls, g[u].st, g[u]._st), pushset(rs, g[u].st, g[u]._st),
g[u].st = g[u]._st = INT_MIN;
}
void build(int u = 1, int l = 1, int r = n) {
g[u]._st = g[u].st = INT_MIN;
if (l == r) {
g[u].mx = a[l];
g[u]._mx = a[l];
return;
}
build(ls, l, mid), build(rs, mid + 1, r);
pushup(u);
}
int L, R;
void add(int v, int u = 1, int l = 1, int r = n) {
if (R < l || r < L) return;
if (L <= l && r <= R) return pushadd(u, v, max(v, 0));
pushdown(u, l, r);
add(v, ls, l, mid), add(v, rs, mid + 1, r);
pushup(u);
}
void tset(int v, int u = 1, int l = 1, int r = n) {
if (R < l || r < L) return;
if (L <= l && r <= R) return pushset(u, v, v);
pushdown(u, l, r);
tset(v, ls, l, mid), tset(v, rs, mid + 1, r);
pushup(u);
}
int qmax(int u = 1, int l = 1, int r = n) {
if (R < l || r < L) return INT_MIN;
if (L <= l && r <= R) return g[u].mx;
pushdown(u, l, r);
return max(qmax(ls, l, mid), qmax(rs, mid + 1, r));
}
int qmaxh(int u = 1, int l = 1, int r = n) {
if (R < l || r < L) return INT_MIN;
if (L <= l && r <= R) return g[u]._mx;
pushdown(u, l, r);
return max(qmaxh(ls, l, mid), qmaxh(rs, mid + 1, r));
}
int main() {
n = rd();
for (int i = 1; i <= n; ++i) a[i] = rd();
build();
int m = rd(), z;
for (int i = 1; i <= m; ++i) {
char op = nc();
while (op == ' ' || op == '\r' || op == '\n') op = nc();
L = rd(), R = rd();
if (op == 'Q')
printf("%d\n", qmax());
else if (op == 'A')
printf("%d\n", qmaxh());
else if (op == 'P')
add(rd());
else
tset(rd());
}
return 0;
}
buildLast update and/or translate time of this article,Check the history editFound smelly bugs? Translation outdated? Wanna contribute with us? Edit this Page on Github peopleContributor of this article OI-wiki translateTranslator of this article Visit the original article! copyrightThe article is available under CC BY-SA 4.0 & SATA ; additional terms may apply.