题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4027
这道题最关键的一个地方就是区间更新!
思路: 一开始看到这题,最先想到的就是单结点更新, 但是,这样做是超时的.其实, 这里有一个地方有点难想到,当某个结点的值为1时,开多少次方都还是1,这样就浪费了很多时间. 所以, 要再加一个标记,如果某个区间里的值全为1, 就不继续往下更新.
以下是AC代码:
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<iomanip>
#define MID (f[rt].l+f[rt].r)>>1
using namespace std;
const int maxn=100000;
struct node{
__int64 sum;
int l,r;
bool k;
}f[maxn<<2];
void PushUp(int rt){
f[rt].sum=f[rt<<1].sum+f[rt<<1|1].sum;
f[rt].k = f[rt<<1].k&&f[rt<<1|1].k;///如果两个子结点都不用更新,那自己也不用更新了
}
void build(int L,int R,int rt){
f[rt].l=L, f[rt].r=R, f[rt].k=false;
if(L==R){
scanf("%I64d",&f[rt].sum);
if(f[rt].sum==1)f[rt].k=true;
return ;
}
int mid=MID;
build(L,mid,rt<<1);
build(mid+1,R,rt<<1|1);
PushUp(rt);
}
void update(int L,int R,int rt){
if(f[rt].k)return;///不用更新了
if(f[rt].l==f[rt].r){
f[rt].sum = sqrt(f[rt].sum*1.0);
if(f[rt].sum==1) f[rt].k=true;
return;
}
int mid=MID;
if(L<=mid) update(L,R,rt<<1);
if(R> mid) update(L,R,rt<<1|1);
PushUp(rt);
}
__int64 query(int L,int R,int rt){
if(L<=f[rt].l&&R>=f[rt].r)
return f[rt].sum;
__int64 ret=0;
int mid=MID;
if(L<=mid) ret+=query(L,R,rt<<1);
if(R> mid) ret+=query(L,R,rt<<1|1);
return ret;
}
int main(){
int n,cas=1;
while(~scanf("%d",&n)){
build(1,n,1);
int m; scanf("%d",&m);
printf("Case #%d:\n",cas++);
while(m--){
int c,x,y; scanf("%d%d%d",&c,&x,&y);
if(x>y)swap(x,y);///这里一定要注意
if(c)printf("%I64d\n",query(x,y,1));
else update(x,y,1);
}
puts("");
}
return 0;
}