题干
维护一个区间,支持两种操作:
- 区间求和;
- 区间开平方(将一个区间内的数全部开平方)。
当然在BZOJ上这道题被加上了奇奇怪怪的背景……
- 区间长度不超过100,000;
- 操作个数不超过200,000;
- 区间内的数不超过1,000,000,000。
题解
最重要的性质:一个1,000,000,000以内的数最多开方7次就会变成1。
所以:预处理每个区间内的数开n次方的和(0 <= n <= 7),进行优化。
(不要随便看代码。不要随便看代码。不要随便看代码。因为很重要所以说三遍。)
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
using namespace std;
//Global Variables & Definitions
typedef long long LL;
int N, M;
int data[100010];
//End Global Variables & Definitions
//Segment Tree
struct Tree {
int l, r;
LL sum[7];
LL s;
int ptr;
int lazy;
} T[400040];
inline LL Sum(int u) {
return ~T[u].ptr ? T[u].sum[T[u].ptr] : T[u].s;
}
void PushUp(int u) {
if(T[u << 1].ptr == T[u << 1 | 1].ptr && ~T[u << 1].ptr) {
T[u].ptr = T[u << 1].ptr;
} else {
T[u].ptr = -1;
T[u].s = Sum(u << 1) + Sum(u << 1 | 1);
}
}
inline void MakeLazy(int u, int v) {
T[u].ptr = T[u].ptr + v; if(T[u].ptr > 6) T[u].ptr = 6;
T[u].lazy = T[u].lazy + v; if(T[u].lazy > 6) T[u].lazy = 6;
}
void PushDown(int u) {
if(!T[u].lazy) return;
MakeLazy(u << 1, T[u].lazy);
MakeLazy(u << 1 | 1, T[u].lazy);
PushUp(u);
T[u].lazy = 0;
}
void Build(int u, int l, int r) {
T[u].l = l; T[u].r = r;
T[u].ptr = 0; T[u].lazy = 0;
if(l == r) {
LL *sum = T[u].sum;
sum[0] = data[l];
for(int i = 1;i < 7;++i) sum[i] = (int)(sqrt(sum[i - 1]));
return;
}
int mid = (l + r) >> 1;
Build(u << 1, l, mid);
Build(u << 1 | 1, mid + 1, r);
for(int i = 0;i < 7;++i) T[u].sum[i] = T[u << 1].sum[i] + T[u << 1 | 1].sum[i];
PushUp(u);
}
LL Query(int u, int l, int r) {
if(l <= T[u].l && r >= T[u].r) return Sum(u);
PushDown(u);
int mid = (T[u].l + T[u].r) >> 1;
LL ans = 0ll;
if(l <= mid) ans += Query(u << 1, l, r);
if(r > mid) ans += Query(u << 1 | 1, l, r);
return ans;
}
void Update(int u, int l, int r) {
if(l <= T[u].l && r >= T[u].r && ~T[u].ptr) { MakeLazy(u, 1); return; }
PushDown(u);
int mid = (T[u].l + T[u].r) >> 1;
if(l <= mid) Update(u << 1, l, r);
if(r > mid) Update(u << 1 | 1, l ,r);
PushUp(u);
}
//End Segment Tree
//Main Structure
inline void ir() {
scanf("%d", &N);
for(int i = 1;i <= N;++i) scanf("%d", &data[i]);
Build(1, 1, N);
}
int main() {
ir();
int x, l, r;
scanf("%d", &M);
for(int i = 0;i < M;++i) {
scanf("%d%d%d", &x, &l, &r);
if(x == 1) {
printf("%lld\n", Query(1, l, r));
} else {
Update(1, l, r);
}
}
return 0;
}