题意:有一个长度为n的序列,有两种操作,第一种把在区间[x,y]之内的所有数,变成它的平方根。第二种操作,查询这个区间内的和。
思路:开始想了怎么区间更新,并没有想法,然后一想,卧槽,每个节点最多只会更新8次左右呀,直接更新就好了,于是暴力更新。统计1的个数,区间为1就不更新了。
坑点:x可能会大于y
http://acm.hdu.edu.cn/showproblem.php?pid=4027
#include <cstdio>
#include <cmath>
#include <iostream>
using namespace std;
const int MAXN = 1e5+5;
struct Node {
int x,y;
int k;
long long sum;
}t[MAXN<<2];
int n,m;
void Push_Up(int rt) {
t[rt].sum = t[rt<<1].sum + t[rt<<1|1].sum;
t[rt].k = t[rt<<1].k + t[rt<<1|1].k;
}
void Build(int x,int y,int rt) {
t[rt].x = x; t[rt].y = y;
if(t[rt].x == t[rt].y) {
scanf("%I64d",&t[rt].sum);
if(t[rt].sum == 1)t[rt].k = 1;
else t[rt].k = 0;
return ;
}
int mid = (x + y) >> 1;
Build(x,mid,rt<<1);
Build(mid+1,y,rt<<1|1);
Push_Up(rt);
}
void Update(int rt,int left,int right) {
if((t[rt].y -t[rt].x + 1) == t[rt].k) return ;
if(t[rt].y == t[rt].x) {
t[rt].sum = (long long)sqrt(t[rt].sum);
if(t[rt].sum == 1) {
t[rt].k = 1;
}
return ;
}
int mid = (t[rt].x + t[rt].y) >> 1;
if(mid >= left) {
Update(rt<<1,left,right);
}
if(mid < right) {
Update(rt<<1|1,left,right);
}
Push_Up(rt);
}
long long Query(int rt,int left,int right) {
if(t[rt].x >= left && t[rt].y <= right) {
return t[rt].sum;
}
long long ans = 0;
int mid = (t[rt].x + t[rt].y) >> 1;
if(mid >= left) {
ans += Query(rt<<1,left,right);
}
if(mid < right) {
ans += Query(rt<<1|1,left,right);
}
return ans;
}
void input() {
Build(1,n,1);
scanf("%d",&m);
int ok,left,right;
for(int i = 1 ; i <= m ; i ++) {
scanf("%d %d %d",&ok,&left,&right);
if(left > right) swap(left,right);
if(ok == 0) {
Update(1,left,right);
}
else {
printf("%I64d\n",Query(1,left,right));
}
}
}
void solve() {
}
int main(void) {
int CASENUM = 1;
while(~scanf("%d",&n)) {
printf("Case #%d:\n",CASENUM++);
input();
solve();
puts("");
}
}