公式

N - 連続部分列の和の最大値 / Maximum Subarray Sum 解説 by sounansya


長さ \(K\) の連続部分列 \(N-K+1\) 個それぞれの操作を遅延セグメント木で管理することを考えます。

各クエリでは \(A_i\) の値を \(x\) に変更しますが、これは \(A_i\) の値を \(x-A_i\) 増やすというように捉えることができます。この値の変更は 0-indexed で \(\max(0,i-K+1)\) 番目から \(\min(N-K,i)\) 番目までの連続部分列の総和がそれぞれ \(x-A_i\) だけ増えることになります。

各変更クエリ後の答えは全ての連続部分列の総和の最大値なので、区間加算・区間 max の遅延セグメント木を用いることでこの問題を \(O(N+Q\log N)\) 時間で解くことができます。

実装例(C++) (\(O(N+(N+Q)\log N)\) 解)

#include <atcoder/lazysegtree>
#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; i < n; i++)

constexpr long INF = 4e18;
long op(long a, long b) { return max(a, b); }
long e() { return 0; }
long mapping(long f, long x) { return f + x; }
long composition(long f, long g) { return f + g; }
long id() { return 0; }
int main() {
	cin.tie(nullptr);
	ios::sync_with_stdio(false);
	int n, k;
	cin >> n >> k;
	vector<long> a(n);
	rep(i, n) cin >> a[i];
	atcoder::lazy_segtree<long, op, e, long, mapping, composition, id> seg(n - k + 1);
	rep(i, n) seg.apply(max(0, i - k + 1), min(n - k + 1, i + 1), a[i]);
	int q;
	cin >> q;
	while (q--) {
		int i;
		long x;
		cin >> i >> x;
		i--;
		seg.apply(max(0, i - k + 1), min(n - k + 1, i + 1), x - a[i]);
		a[i] = x;
		cout << seg.all_prod() << '\n';
	}
}

投稿日時:
最終更新: