LOJ6281. 数列分块入门 5 题解
涉及操作:
- 区间开方;
- 区间求和。
解题思路:
主要思路:\(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;
}