题目大意:给你N个数,两种操作
0 l r:[l,r]内的所有数开根
1 l r:[l,r]内的数字的和
解题思路:不断开根的话,最多只需要6次,6次以上的,都是1了,所以维护的是当前区间被开了几次根的和
这个可以先预处理下,先预处理所有所有情况的开根和(不超过7次),然后在用一个标记,标记该区间被开了几次根,求和的时候就可以依据此标记来找和了
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100010;
LL sum[10][N << 2], val[N], level;
int add[N << 2], cnt[N << 2];
int n, q;
void PushUp(int u) {
for (int i = 0; i <= level; i++)
sum[i][u] = sum[i][u << 1] + sum[i][u << 1 | 1];
}
void build(int u, int l, int r) {
add[u] = cnt[u] = 0;
if (l == r) {
sum[0][u] = val[l];
if (val[l] == 0) {
for (int i = 1; i <= level; i++)
sum[i][u] = 0;
return ;
}
int i;
for (i = 1; sum[i - 1][u] > 1; i++) sum[i][u] = sqrt((double)sum[i - 1][u]);
for (; i <= level; i++) sum[i][u] = 1;
return ;
}
int mid = (l + r) >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
PushUp(u);
}
void PushDown(int u) {
if (add[u] != 0) {
add[u << 1] += add[u];
add[u << 1 | 1] += add[u];
cnt[u << 1] += add[u];
cnt[u << 1 | 1] += add[u];
add[u] = 0;
}
}
void Modify(int u, int l, int r, int L, int R) {
if (l == L && r == R) {
add[u] += 1;
cnt[u] += 1;
return ;
}
PushDown(u);
int mid = (l + r) >> 1;
if (R <= mid) Modify(u << 1, l, mid, L, R);
else if (L > mid) Modify(u << 1 | 1, mid + 1, r, L, R);
else {
Modify(u << 1, l, mid, L, mid);
Modify(u << 1 | 1, mid + 1, r, mid + 1, R);
}
}
LL Query(int u, int l, int r, int L, int R) {
if (L == l && r == R) {
if (cnt[u] > level) cnt[u] = level;
if (cnt[u] == level || l == r) return sum[cnt[u]][u];
PushDown(u);
int mid = (l + r) >> 1;
return Query(u << 1, l, mid, l, mid) + Query(u << 1 | 1, mid + 1, r, mid + 1, r);
}
PushDown(u);
int mid = (l + r) >> 1;
if (R <= mid) return Query(u << 1, l, mid, L, R);
else if (L > mid) return Query(u << 1 | 1, mid + 1, r, L, R);
else return Query(u << 1, l, mid, L, mid) + Query(u << 1 | 1, mid + 1, r, mid + 1, R);
}
void init() {
LL Max = 0;
for (int i = 1; i <= n; i++) {
scanf("%lld", &val[i]);
Max = max(Max, val[i]);
}
for (level = 1; Max > 1; level++) Max = sqrt((double)Max);
build(1, 1, n);
}
int cas = 1;
void solve() {
scanf("%d", &q);
int op, a, b;
printf("Case #%d:\n", cas++);
while (q--) {
scanf("%d%d%d", &op, &a, &b);
if (a > b) swap(a, b);
if (op) printf("%lld\n", Query(1, 1, n, a, b));
else Modify(1, 1, n, a, b);
}
printf("\n");
}
int main() {
while (scanf("%d", &n) != EOF) {
init();
solve();
}
return 0;
}