[cf 1136] E. Nastya Hasn't Written a Legend

题意

给两个数组分别为\(a\)\(k\),有若干次操作:

1.给\(a_x\)加上\(y\),并以此对\(a_{x + i}(i \ge 1)\)赋值为\(\max \{a_{x + i}, a_{x + i - 1} + k_{x + i - 1}\}\)

2.询问区间\([l, r]\)\(a_i\)的和。

题解

自闭了啊。

考虑把原序列分成若干个块,对于每个块内必须满足,除最后一个位置的所有位置\(i\)\(a_i + k_i = a_i + 1\)。刚开始可以看成有\(n\)个块。

每次修改的时候,直接对每个块内用线段树修改,块与块之间可能有合并(最多合并\(O(n + q)\)次),然后每一次修改可能会产生\(O(1)\)个新的块。所有块用一个set维护一下。所以总复杂度是\(O((n + q) \log n)\)的。

#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
using namespace std;
typedef long long ll;
typedef pair <int, int> pii;
 
inline int read () {
    static int x;
    scanf("%d", &x);
    return x;
}
const int N = 1e5 + 5, inf = 2e9;
int n, q, a[N], k[N]; ll pres[N];
set <pii> block;
ll s[N << 2], tag[N << 2];
#define mid ((l + r) >> 1)
#define lc (o << 1)
#define rc (o << 1 | 1)
#define ls lc, l, mid
#define rs rc, mid + 1, r
inline void pushdown (int o, int l, int r) {
    s[lc] += tag[o] * (mid - l + 1), tag[lc] += tag[o];
    s[rc] += tag[o] * (r - mid), tag[rc] += tag[o];
    tag[o] = 0;
}
inline void build (int o, int l, int r) {
    if (l == r) {s[o] = a[l]; return;}
    build(ls), build(rs);
    s[o] = s[lc] + s[rc];
}
inline void modify (int o, int l, int r, int x, int y, ll v) {
    if (x <= l && r <= y) {s[o] += v * (r - l + 1), tag[o] += v; return;}
    if (tag[o]) pushdown(o, l, r);
    if (x <= mid) modify(ls, x, y, v);
    if (y > mid) modify(rs, x, y, v);
    s[o] = s[lc] + s[rc];
}
inline ll query (int o, int l, int r, int x, int y) {
    if (x <= l && r <= y) return s[o];
    if (tag[o]) pushdown(o, l, r);
    ll ret = 0;
    if (x <= mid) ret += query(ls, x, y);
    if (y > mid) ret += query(rs, x, y);
    return ret;
}

void alter (int x, int v) {
    set <pii> :: iterator b; int l, r;
    b = block.lower_bound(mp(x, inf)), --b;
    l = b->fi, r = b->se;
    block.erase(b);
    if (l < x) block.insert(mp(l, x - 1));
    modify(1, 1, n, x, r, v);
    for ( ; r < n; ) {
        ll s = query(1, 1, n, r, r), t = query(1, 1, n, r + 1, r + 1), delta = s + k[r] - t;
        if (delta < 0) break;
        b = block.lower_bound(mp(r + 1, r + 1));
        l = b->fi, r = b->se;
        block.erase(b);
        modify(1, 1, n, l, r, delta);
    }
    block.insert(mp(x, r));
}
int main() {
    n = read();
    for (int i = 1; i <= n; ++i)
        a[i] = read(), pres[i] = pres[i - 1] + a[i];
    for (int i = 1; i < n; ++i) k[i] = read();
    for (int i = 1; i <= n; ++i) block.insert(mp(i, i));
    build(1, 1, n); 
    char op[5]; int x, y;
    for (int _ = read(); _; --_) {
        scanf("%s", op), x = read(), y = read();
        if (op[0] == '+') alter(x, y); else
        printf("%lld\n", query(1, 1, n, x, y));
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/psimonw/p/10727393.html