1. 程式人生 > 其它 >LOJ6283. 數列分塊入門 7 題解

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;
}