LOJ6283. 数列分块入门 7 题解

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

设计操作:

  1. 区间加法
  2. 区间乘法
  3. 单点查询

解题思路:

\(X_i\) 维护第 \(i\) 个分块当前乘的数,用 \(Y_i\) 维护第 \(i\) 个分块当前加的数。

若当前乘了 \(X_i\),加了 \(Y_i\),则加了 \(c\) 之后 \(\Rightarrow\) 乘的数不变,加的数变成了 \(Y_i + c\)

若当前乘了 \(X_i\),加了 \(Y_i\),则乘了 \(c\) 之后 \(\Rightarrow\) 乘的数变成了 \(X_i \times c\),加的数变成了 \(Y_i \times c\)

而如果加或乘的区间不完全包含,则更新所有 \(a_i\),同时还原对应的分段 \(p\)\(X_p = 1, Y_p = 0\)(因为乘法的基数为 \(1\))。

示例程序:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
const long long MOD = 10007;
int n, blo, bl[maxn];
long long a[maxn], X[505], Y[505];


// 将第p个分块的修改还原到分块中的每个元素
void recover(int p) {
    for (int i = (p-1)*blo+1; i <= min(p*blo,n); i ++) {
        a[i] = (a[i] * X[p] % MOD + Y[p]) % MOD;
    }
    X[p] = 1;
    Y[p] = 0;
}

void add(int l, int r, int c) {
    recover(bl[l]);
    for (int i = l; i <= min(bl[l]*blo, r); i ++)
        a[i] = (a[i] + c) % MOD;
    if (bl[l] != bl[r]) {
        recover(bl[r]);
        for (int i = (bl[r]-1)*blo+1; i <= r; i ++)
            a[i] = (a[i] + c) % MOD;
    }
    for (int i = bl[l]+1; i < bl[r]; i ++) {
        Y[i] = (Y[i] + c) % MOD;
    }
}

void multi(int l, int r, int c) {
    recover(bl[l]);
    for (int i = l; i <= min(bl[l]*blo, r); i ++)
        a[i] = (a[i] * c) % MOD;
    if (bl[l] != bl[r]) {
        recover(bl[r]);
        for (int i = (bl[r]-1)*blo+1; i <= r; i ++)
            a[i] = (a[i] * c) % MOD;
    }
    for (int i = bl[l]+1; i < bl[r]; i ++) {
        X[i] = X[i] * c % MOD;
        Y[i] = Y[i] * c % MOD;
    }
}

int query(int p) {
    // 这样查询是根号n的
    // recover(bl[p]);
    // return a[p];
    // 这样查询是O(1)的
    return (a[p] * X[bl[p]] + Y[bl[p]]) % MOD;
}

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;
    }
    for (int i = 1; i <= bl[n]; i ++) X[i] = 1; // 乘法的基数是1
    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 if (op == 1) {
            multi(l, r, c);
        }
        else {
            cout << query(r) << endl;
        }
    }
    return 0;
}
posted @ 2021-11-08 22:15  quanjun  阅读(47)  评论(0编辑  收藏  举报