hdu4027 线段树(区间开平方,区间求和)
本题的线段树区间更新不能用区间更新做,因为不满足:区间和的更新==区间内每个数更新的和
所以实际上是单点更新,单点更新不是退化成On2了吗?
不,因为要知道一点64位整数开平方七八次就变成1了,退化成1的区间我们不去更新他,正确计算复杂度为O(10*m*log(n));
类似开方这些变化很快的,thinking~~
1 #include<stdio.h> 2 #include<string.h> 3 #include<math.h> 4 #include<algorithm> 5 #define LL long long 6 using namespace std; 7 LL sumv[400005],ok[400005],a[100005]; 8 void build(LL o,LL l,LL r) 9 { 10 LL mid=l+(r-l)/2; 11 if (l==r){ 12 sumv[o]=a[l]; 13 ok[o]=a[l]<=1?1:0; 14 } 15 else{ 16 build(o*2,l,mid); 17 build(o*2+1,mid+1,r); 18 sumv[o]=sumv[o*2]+sumv[o*2+1]; 19 ok[o]=(ok[o*2]&&ok[o*2+1]); 20 } 21 } 22 void update(LL o,LL l,LL r,LL y1,LL y2) 23 { 24 LL mid=l+(r-l)/2; 25 if (l==r){ 26 sumv[o]=(LL)sqrt(1.0*sumv[o]); 27 ok[o]=sumv[o]<=1?1:0; 28 } 29 else{ 30 if (y1<=mid&&ok[o*2]==0) update(o*2,l,mid,y1,y2); 31 if (y2>mid&&ok[o*2+1]==0) update(o*2+1,mid+1,r,y1,y2); 32 sumv[o]=sumv[o*2]+sumv[o*2+1]; 33 ok[o]=(ok[o*2]&&ok[o*2+1]); 34 } 35 } 36 LL query(LL o,LL l,LL r,LL y1,LL y2) 37 { 38 LL mid=l+(r-l)/2,tmp=0; 39 if (y1<=l&&y2>=r) return sumv[o]; 40 if (y1<=mid) tmp+=query(o*2,l,mid,y1,y2); 41 if (y2>mid) tmp+=query(o*2+1,mid+1,r,y1,y2); 42 return tmp; 43 } 44 int main() 45 { 46 LL t=0,n,i,m,k,l,r; 47 while (~scanf("%I64d",&n)) 48 { 49 for (i=1;i<=n;i++) scanf("%I64d",&a[i]); 50 memset(sumv,0,sizeof(sumv)); 51 memset(ok,0,sizeof(ok)); 52 build(1,1,n); 53 printf("Case #%I64d:\n",++t); 54 scanf("%I64d",&m); 55 while (m--) 56 { 57 scanf("%I64d%I64d%I64d",&k,&l,&r); 58 if (l>r) {i=l; l=r; r=i; } 59 if (k==0) update(1,1,n,l,r); 60 else printf("%I64d\n",query(1,1,n,l,r)); 61 } 62 printf("\n"); 63 } 64 return 0; 65 }