题目链接:点击链接
题意:
- 有n个数,现在有一种操作,将这n个数中的一个区间[x, y],每个数都开平方。询问区间的和。
思路:
建树的时候,当前节点保存了对应区间的和。更新的时候,若当前节点对应的区间为[l, r],如果区间和小于(r-l+1),不往下更新,反之往下更新。
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 100000 + 10;
typedef long long ll;
ll tree[maxn<<2];
void pushup(int rt){
tree[rt] = tree[rt<<1] + tree[rt<<1|1];
}
void build(int rt, int l, int r){
if(l==r){
scanf("%lld", &tree[rt]);
}
else{
int mid = (l+r) / 2;
build(rt<<1, l, mid);
build(rt<<1|1, mid+1, r);
pushup(rt);
}
}
void update(int rt, int a, int b, int l, int r){
int mid = (l+r)>>1;
if(a<=l && r<=b){
if(l==r){
tree[rt] = (ll)sqrt(tree[rt]);
return;
}
if(tree[rt]>(r-l+1)){
if(a <= mid) update(rt<<1, a, b, l, mid);
if(mid < b) update(rt<<1|1, a, b, mid+1, r);
pushup(rt);
}
}
else{
if(a <= mid) update(rt<<1, a, b, l, mid);
if(mid < b) update(rt<<1|1, a, b, mid+1, r);
pushup(rt);
}
}
ll query(int rt, int a, int b, int l, int r){
if(a<=l && r<=b){
return tree[rt];
}
else{
int mid = (l+r)>>1;
ll ans = 0;
if(a<=mid) ans += query(rt<<1, a, b, l, mid);
if(mid<b) ans += query(rt<<1|1, a, b, mid+1, r);
return ans;
}
}
int main(){
int n, q, opt, a, b, Case=0;
while(scanf("%d", &n)!=EOF){
build(1, 1, n);
scanf("%d", &q);
printf("Case #%d:\n", ++Case);
for(int i=0; i<q; ++i){
scanf("%d%d%d", &opt, &a, &b);
if(opt==0){
if(a>b) swap(a, b);
update(1, a, b, 1, n);
}
if(opt==1){
if(a>b) swap(a, b);
printf("%lld\n", query(1, a, b, 1, n));
}
}
printf("\n");
}
return 0;
}