LOJ6281. 數列分塊入門 5 題解
阿新 • • 發佈:2021-11-08
涉及操作:
- 區間開方;
- 區間求和。
解題思路:
主要思路:\(2^{32}\) 次方內的數最多開 \(7\) 次方都會變成 \(1\)。
用 \(tag_i\) 表示第 \(i\) 個分塊的整體開方次數,則 \(tag_i \ge 7\) 時這個分塊中的所有元素都為 \(1\)。
示例程式:
#include <bits/stdc++.h> using namespace std; const int maxn = 50050; int n, blo, bl[maxn], a[maxn], sum[505], tag[505]; /** tag[i]記錄第i個分塊的數值和 sum[i]第i個塊所有單獨增加的元素和 */ void kaifang(int l, int r) { for (int i = l; i <= min(bl[l]*blo, r); i ++) { sum[bl[i]] -= a[i]; a[i] = sqrt(a[i]); sum[bl[i]] += a[i]; } if (bl[l] != bl[r]) { for (int i = (bl[r]-1)*blo+1; i <= r; i ++) { sum[bl[i]] -= a[i]; a[i] = sqrt(a[i]); sum[bl[i]] += a[i]; } } for (int i = bl[l]+1; i < bl[r]; i ++) { tag[i] ++; if (tag[i] < 7) { for (int j = (i-1)*blo+1; j <= i*blo; j ++) { sum[bl[j]] -= a[j]; a[j] = sqrt(a[j]); sum[bl[j]] += a[j]; } } } } int query(int l, int r) { int ans = 0; for (int i = l; i <= min(bl[l]*blo, r); i ++) ans += a[i]; if (bl[l] != bl[r]) for (int i = (bl[r]-1)*blo+1; i <= r; i ++) ans += a[i]; for (int i = bl[l]+1; i < bl[r]; i ++) ans += sum[i]; return ans; } 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) kaifang(l, r); else cout << query(l, r) << endl; } return 0; }