题目:
http://acm.hdu.edu.cn/showproblem.php?pid=4027
先说这个题的关键:
- 这道题不同于普通的成段更新,需要对每一个值进行求根操作,而如果每次都对区间的每个点进行求根操作的话,复杂度肯定很高。所以,第一个关键点就是,一个数不断开方后的结果,最后一定会变成1的,即便是2的64次方这么大的数,开方7次后也会变成1。所以,我们对一个点最多也就更新7次。
- 一个很坑的点就是,题目并没有告诉x>y,这个错误很隐秘,所以仔细读题很重要。。。
大部分代码都是正常的线段树操作,不同的是,lazy数组记录该节点维护的区间是否还需要更新,pushup函数中,有个&&操作,就是当两子节点的lazy值都为1,父节点也为1,说明这两个数都不需要操作了。
update中要注意只有当lazy值不为1的时候才需要更新下去,若为1则说明这段区间内的所有值已经都为1,不需要再进行开方运算了。
1 #include<stdio.h> 2 #include<math.h> 3 #define maxn 100100 4 #define lson l,m,rt*2 5 #define rson m+1,r,rt*2+1 6 long long tree[maxn<<2]; 7 int lazy[maxn<<2]; 8 void pushup(int rt){ 9 tree[rt] = tree[rt*2]+tree[rt*2+1]; 10 lazy[rt] = lazy[rt*2]&&lazy[rt*2+1]; 11 } 12 void build(int l,int r,int rt){ 13 lazy[rt] = 0; 14 if(l==r){ 15 scanf("%lld",&tree[rt]); 16 return; 17 } 18 int m = (l+r)/2; 19 build(lson); 20 build(rson); 21 pushup(rt); 22 } 23 void update(int a,int b,int l,int r,int rt){ 24 if(l==r){ 25 tree[rt] = sqrt(tree[rt]); 26 if(tree[rt]<=1){ 27 lazy[rt] = 1; 28 } 29 return; 30 } 31 int m = (l+r)/2; 32 if(a<=m&&!lazy[rt]) 33 update(a,b,lson); 34 if(b>m&&!lazy[rt]) 35 update(a,b,rson); 36 pushup(rt); 37 } 38 long long query(int a,int b,int l,int r,int rt){ 39 if(a<=l&&b>=r) 40 return tree[rt]; 41 int m = (l+r)/2; 42 long long ret = 0; 43 if(a<=m) 44 ret += query(a,b,lson); 45 if(b>m) 46 ret += query(a,b,rson); 47 return ret; 48 } 49 int main(){ 50 int n,cnt = 1;; 51 while(scanf("%d",&n)!=EOF){ 52 build(1,n,1); 53 int m; 54 scanf("%d",&m); 55 int flag = 1; 56 while(m--){ 57 int t,x,y; 58 scanf("%d%d%d",&t,&x,&y); 59 if(x>y) 60 x^=y^=x^=y; 61 if(t==0){ 62 update(x,y,1,n,1); 63 }else{ 64 if(flag == 1){ 65 printf("Case #%d:\n",cnt); 66 flag = 0; 67 } 68 printf("%lld\n",query(x,y,1,n,1)); 69 } 70 } 71 cnt++; 72 printf("\n"); 73 } 74 return 0; 75 }
时间: 2024-10-18 21:44:51