这道题之前在camp的时候听人讲过,因为根号运算n衰减的很快,所以在极少数的操作内它就会变成1,所以当整个区间内的值都变成1时直接返回,反之暴力更新叶子结点就好
#include
#include
#include
using namespace std;
typedef long long ll;
const int N = 100100;
ll sum[N * 4];
void pushup(int rt){
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
void build(int l, int r, int rt){
if(l == r){
scanf("%lld", &sum[rt]);
return ;
}
int m = (l + r) >> 1;
build(l, m, rt << 1);
build(m + 1, r, rt << 1 | 1);
pushup(rt);
}
void update(int L, int R, int l, int r, int rt){
if(l == r){
sum[rt] = sqrt(sum[rt]);
return ;
}
if(L <= l && R >= r && sum[rt] == r - l + 1)
return ;
int m = (l + r) >> 1;
if(L <= m)
update(L, R, l, m, rt << 1);
if(R > m)
update(L, R, m + 1, r, rt << 1 | 1);
pushup(rt);
}
ll query(int L, int R, int l, int r, int rt){
if(L <= l && r <= R)
return sum[rt];
int m = (l + r) >> 1;
ll s = 0;
if(L <= m)
s += query(L, R, l, m, rt << 1);
if(R > m)
s += query(L, R, m + 1, r, rt << 1 | 1);
return s;
}
int main(){
int n, m, cas = 0;
while(~ scanf("%d", &n)){
build(1, n, 1);
scanf("%d", &m);
int a, b, c;
printf("Case #%d:\n", ++ cas);
while(m --){
scanf("%d %d %d", &a, &b, &c);
int bb = min(b, c), cc = max(b, c);
if(a)
printf("%lld\n", query(bb, cc, 1, n, 1));
else
update(bb, cc, 1, n, 1);
}
printf("\n");
}
return 0;
}