LOJ #6280. 数列分块入门 4
思路&&代码
区间修改+区间查值
这个就是在数列分块入门(1)的基础上加了一个(sum[i])
先分块,把这(n)个数分成(sqrt{n})个块,用(add[i])表示这个块修改值的和(增量标记),用(sum[i])表示这个块内数的和
如果第一题会了,这个也很容易明白,就不讲了(qwq)
时间复杂度(O(nsqrt{n}))
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#define int long long
using namespace std;
const int A = 1e5 + 11;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for ( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, m, t;
int a[A], sum[A], add[A], L[A], R[A], pos[A];
void change(int l, int r, int c) {
int p = pos[l], q = pos[r];
if(p == q) {
for(int i = l; i <= r; i++) a[i] += c;
sum[p] += (r - l + 1) * c; return;
}
for(int i = p + 1; i < q; i++) add[i] += c;
for(int i = l; i <= R[p]; i++) a[i] += c; sum[p] += (R[p] - l + 1) * c;
for(int i = L[q]; i <= r; i++) a[i] += c; sum[q] += (r - L[q] + 1) * c;
}
int ask(int l, int r, int c) {
int ans = 0, p = pos[l], q = pos[r];
if(p == q) {
for(int i = l; i <= r; i++) ans += a[i], ans %= (c + 1);
ans += add[p] * (r - l + 1);
return ans % (c + 1);
}
for(int i = p + 1; i < q; i++) ans += sum[i] + add[i] * (R[i] - L[i] + 1), ans %= (c + 1);
for(int i = l; i <= R[p]; i++) ans += a[i], ans %= (c + 1); ans += add[p] * (R[p] - l + 1), ans %= (c + 1);
for(int i = L[q]; i <= r; i++) ans += a[i], ans %= (c + 1); ans += add[q] * (r - L[q] + 1), ans %= (c + 1);
return ans % (c + 1);
}
signed main() {
n = read();
for(int i = 1; i <= n; i++) a[i] = read();
t = sqrt(n);
for(int i = 1; i <= t; i++) {
L[i] = (i - 1) * sqrt(n) + 1;
R[i] = i * sqrt(n);
}
if(R[t] < n) t++, L[t] = R[t - 1] + 1, R[t] = n;
for(int i = 1; i <= t; i++) {
for(int j = L[i]; j <= R[i]; j++) {
pos[j] = i;
sum[i] += a[j];
}
}
m = n;
while(m--) {
int opt, l, r, c;
opt = read(), l = read(), r = read(), c = read();
if(opt == 0) change(l, r, c);
else cout << ask(l, r, c) << "
";
}
}