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 }
View Code

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4027

posted on 2015-01-04 16:05  xiao_xin  阅读(175)  评论(0编辑  收藏  举报

导航