[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;
}
posted @ 2019-04-18 08:16  psimonw  阅读(201)  评论(0编辑  收藏  举报