LOJ6280. 数列分块入门 4 题解

题目链接:https://loj.ac/p/6280

涉及操作:

  1. 区间加法;
  2. 区间求和。

解题思路:

数列分块。

需要:

  • \(sum_i\) 表示第 \(i\) 个分块单独累加的数值和;
  • \(tag_i\) 表示第 \(i\) 个分块整体累加的数值和(就是分块 \(i\) 内的每个数都会增加 \(tag_i\))。

示例程序:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 50050;
int n, blo, bl[maxn];
long long a[maxn], sum[505], tag[505];

/**
tag[i]记录第i个分块的数值和
sum[i]第i个块所有单独增加的元素和
*/

void add(int l, int r, long long val) {
    for (int i = l; i <= min(bl[l]*blo, r); i ++)
        a[i] += val, sum[bl[i]] += val;
    if (bl[l] != bl[r])
        for (int i = (bl[r]-1)*blo+1; i <= r; i ++)
            a[i] += val, sum[bl[i]] += val;
    for (int i = bl[l]+1; i < bl[r]; i ++)
        tag[i] += val;
}

long long query(int l, int r, long long M) {
    long long ans = 0;
    for (int i = l; i <= min(bl[l]*blo, r); i ++)
        ans += a[i] + tag[bl[i]];
    if (bl[l] != bl[r])
        for (int i = (bl[r]-1)*blo+1; i <= r; i ++)
            ans += a[i] + tag[bl[i]];
    for (int i = bl[l]+1; i < bl[r]; i ++)
        ans += sum[i] + tag[i] * blo;
    return (ans % M + M) % M;
}

int main() {
    ios::sync_with_stdio(0);
    cin >> n;
    blo = sqrt(n);
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
        bl[i] = (i - 1) / blo + 1;
        sum[bl[i]] += a[i];
    }
    for (int i = 0; i < n; i ++) {
        int op, l, r, c;
        cin >> op >> l >> r >> c;
        if (op == 0) add(l, r, c);
        else cout << query(l, r, c+1) << endl;
    }
    return 0;
}
posted @ 2021-11-08 18:28  quanjun  阅读(81)  评论(0编辑  收藏  举报