HDU

来源:互联网 发布:知否 知否应是绿肥红瘦 编辑:程序博客网 时间:2024/05/16 07:17
线段树中等题
题意:
n个数,两种操作:0 b c表示将[b,c]区间的数开方,1 b c表示询问[b,c]区间的和。
开始总是超时然后借鉴了别人的博客,有两个坑点一个是输出,还是一个是b可能大于c,这时要把他俩交换一下。还有本题主要思路是能想到long long 范围的数开根号最多不超过7次。
具体看代码
#include <stdio.h>#include <iostream>#include <algorithm>#include <string.h>#include <math.h>using namespace std;long long a[100005*4];bool flag[100005*4];//标记当前区间是否还需要开根号int n;void uprt(int k){flag[k]=(flag[k<<1]||flag[k<<1|1]);//如果两个字区间任何一个需要开根号,则把大区间也标记 a[k]=a[k<<1]+a[k<<1|1];}void built(int l,int r,int k){if(l==r){scanf("%lld",&a[k]);flag[k]=1;if(a[k]<=1)//如果此区间下的值小于等于1,则以后都不需要开根号,因为根号1等于1 flag[k]=0;return ;}int mid=(l+r)/2;built(l,mid,k<<1);built(mid+1,r,k<<1|1);uprt(k);}long long search(int l,int r,int ll,int rr,int k)//查询操作,和往常一样 {if(l==ll&&r==rr){return a[k];}int mid=(l+r)/2;if(mid>=rr) return search(l,mid,ll,rr,k<<1);else if(mid<ll) return search(mid+1,r,ll,rr,k<<1|1);else return search(l,mid,ll,mid,k<<1)+search(mid+1,r,mid+1,rr,k<<1|1);}void add(int l,int r,int ll,int rr,int k)//更新 {if(ll==l&&r==rr){if(!flag[k])//如果当前区间不需要更新则返回 return ;}if(l==r)//更新到叶子结点 {a[k]=floor(sqrt(a[k]));if(a[k]<=1)flag[k]=0;return ;}int mid=(l+r)/2;if(mid>=rr){add(l,mid,ll,rr,k<<1);}else if(mid<ll){add(mid+1,r,ll,rr,k<<1|1);}else {add(l,mid,ll,mid,k<<1);add(mid+1,r,mid+1,rr,k<<1|1);}uprt(k);}int main(){int cas=1;while(scanf("%d",&n)!=EOF){built(1,n,1);int m;scanf("%d",&m);printf("Case #%d:\n",cas++);while(m--){int x,y,z;scanf("%d%d%d",&x,&y,&z);if(y>z)swap(z,y); if(x==1)//0区间开根号  1区间求和{printf("%lld\n",search(1,n,y,z,1));}else{add(1,n,y,z,1);}}puts("");  }return 0;}

原创粉丝点击