题意
给两个数组分别为\(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;
}
[cf 1136] E. Nastya Hasn't Written a Legend
原文地址:https://www.cnblogs.com/psimonw/p/10727393.html
时间: 2024-10-31 18:18:42