題幹
維護一個區間,支持兩種操作:
- 區間求和;
- 區間開平方(將一個區間內的數全部開平方)。
當然在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;
}