题解:P13979 数列分块入门 4
inperfectTower · · 题解
记
简要题意
有一个数列,你需要支持区间加上某一个数和查询区间和。
解法
~我会线段树!~
考虑 区间修改,单点查询 中引入的分块思想,我们以
由于我们要查询区间和,所以需要维护一个块内和。与 区间修改,单点查询 中一样,我们需要维护一个懒标记用于区间修改。在区间修改的时候块内的和直接加上
区间查询的时候,散块暴力处理,整块直接查询块内和即可。
这是
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int kB = 450; // 调试的时候可以把 kB 调小,但是记得提交时要改回去
int n, arr[300030], op, l, r, c, bt[300030], bel[300030], bs[300030], blen[300030];
signed main() {
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> arr[i];
bel[i] = (i + kB - 1) / kB;
bs[bel[i]] += arr[i], blen[bel[i]]++;
}
for(int i = 1; i <= n; i++) {
cin >> op >> l >> r >> c;
if(op == 0) {
if(bel[l] == bel[r]) {
for(int j = l; j <= r; j++) arr[j] += c, bs[bel[j]] += c;
}else {
if(bel[l] == bel[l - 1]) for(; bel[l] == bel[l - 1]; l++) arr[l] += c, bs[bel[l]] += c;
if(bel[r] == bel[r + 1]) for(; bel[r] == bel[r + 1]; r--) arr[r] += c, bs[bel[r]] += c;
for(int j = bel[l]; j <= bel[r]; j++) bt[j] += c, bs[j] += blen[j] * c; // 注意可能出现长度 < kB 的块
}
}else {
int ans = 0;
if(bel[l] == bel[r]) {
for(int j = l; j <= r; j++) ans += arr[j] + bt[bel[j]];
}else {
if(bel[l] == bel[l - 1]) for(; bel[l] == bel[l - 1]; l++) ans += arr[l] + bt[bel[l]];
if(bel[r] == bel[r + 1]) for(; bel[r] == bel[r + 1]; r--) ans += arr[r] + bt[bel[r]];
for(int j = bel[l]; j <= bel[r]; j++) ans += bs[j];
}
cout << (ans % (c + 1) + (c + 1)) % (c + 1) << '\n';
}
}
return 0;
}