题目链接: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; }