考虑到每个负的点权都只会有一次变为正的,于是树剖+线段树维护当前子树的绝对值和和子树中负数的最大值就好。
Code
#define lc (p << 1)
#define rc (p << 1 | 1)
#define mid ((l + r) >> 1)
ll ss[N << 2], mx[N << 2], tg[N << 2], tot[N << 2];
inline void pushup(int p) {
ss[p] = ss[lc] + ss[rc];
mx[p] = max(mx[lc], mx[rc]);
tot[p] = tot[lc] + tot[rc];
}
inline void pushnow(int p, ll v) {
ss[p] += tot[p] * v;
if (mx[p] > -inf) mx[p] += v;
tg[p] += v;
}
inline void pushdown(int p) {
if (tg[p]) {
pushnow(lc, tg[p]);
pushnow(rc, tg[p]);
tg[p] = 0;
}
}
inline void build(int p, int l, int r) {
if (l == r) {
ss[p] = a[pred[l]];
mx[p] = ss[p] >= 0 ? -inf : ss[p];
tot[p] = 1;
if (ss[p] < 0) ss[p] = -ss[p], tot[p] = -1;
return;
}
build(lc, l, mid), build(rc, mid + 1, r);
pushup(p);
}
int ql, qr;
inline void upd(int p, int l, int r, ll v) {
if (ql <= l && r <= qr) return pushnow(p, v);
pushdown(p);
if (qr <= mid) upd(lc, l, mid, v);
else if (ql > mid) upd(rc, mid + 1, r, v);
else upd(lc, l, mid, v), upd(rc, mid + 1, r, v);
pushup(p);
}
inline ll qry(int p, int l, int r) {
if (ql <= l && r <= qr) return ss[p];
pushdown(p);
if (qr <= mid) return qry(lc, l, mid);
if (ql > mid) return qry(rc, mid + 1, r);
return qry(lc, l, mid) + qry(rc, mid + 1, r);
}
inline void Fix(int p, int l, int r) {
if (mx[p] < 0) return;
if (l == r) {
if (ss[p] < 0) {
mx[p] = -inf;
ss[p] = -ss[p];
tot[p] = 1;
}
return;
}
pushdown(p);
Fix(lc, l, mid), Fix(rc, mid + 1, r);
pushup(p);
}