HDU 4027

题目:

http://acm.hdu.edu.cn/showproblem.php?pid=4027

先说这个题的关键:

  1. 这道题不同于普通的成段更新,需要对每一个值进行求根操作,而如果每次都对区间的每个点进行求根操作的话,复杂度肯定很高。所以,第一个关键点就是,一个数不断开方后的结果,最后一定会变成1的,即便是2的64次方这么大的数,开方7次后也会变成1。所以,我们对一个点最多也就更新7次。
  2. 一个很坑的点就是,题目并没有告诉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

HDU 4027的相关文章

HDU 4027 Can you answer these queries? (线段树+区间点修改)

题意:给你 n 个数,m个询问(c,x,y) c==0 把x,y区间的值变为原来的平方根(向下取整) c==1 计算x,y区间的和. 利用1的开方永远为1剪枝.. #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> //#include<map> #include<cmath> #include<iostream> #include

HDU 4027 Can you answer these queries?(线段树,区间更新,区间查询)

题目 线段树 简单题意: 区间(单点?)更新,区间求和 更新是区间内的数开根号并向下取整 这道题不用延迟操作 //注意: //1:查询时的区间端点可能前面的比后面的大: //2:优化:因为每次更新都是开平方,同一个数更新有限次数就一直是1了,所以可以这样优化 #include <stdio.h> #include<math.h> #define N 100010 #define LL __int64 #define lson l,m,rt<<1 #define rson

HDU 4027 Can you answer these queries? 线段树裸题

题意: 给定2个操作 0.把区间的每个数sqrt 2.求和 因为每个数的sqrt次数很少,所以直接更新到底,用个标记表示是否更新完全(即区间内的数字只有0,1就不用再更新了) #include<stdio.h> #include<iostream> #include<algorithm> #include<vector> #include<cmath> #include<queue> #include<set> #incl

HDU 4027—— Can you answer these queries?——————【线段树区间开方,区间求和】

Can you answer these queries? Time Limit:2000MS     Memory Limit:65768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 4027 Description A lot of battleships of evil are arranged in a line before the battle. Our commander decides to use

H - Can you answer these queries? HDU 4027 (线段树+延迟标记+开根号的速度)

H - Can you answer these queries? Time Limit:2000MS Memory Limit:65768KB 64bit IO Format:%I64d & %I64u Submit Status Practice HDU 4027 Description A lot of battleships of evil are arranged in a line before the battle. Our commander decides to use our

HDU 4027 Can you answer these queries?(线段树区间开方)

Can you answer these queries? Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) Total Submission(s): 16260    Accepted Submission(s): 3809 Problem Description A lot of battleships of evil are arranged in a line befor

HDU 4027 Can you answer these queries?(线段树的单点更新+区间查询)

题目链接 题意 : 给你N个数,进行M次操作,0操作是将区间内的每一个数变成自己的平方根(整数),1操作是求区间和. 思路 :单点更新,区间查询,就是要注意在更新的时候要优化,要不然会超时,因为所有的数开几次方之后都会变成1,所以到了1不用没完没了的更新. 1 //HDU 4027 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <iostream> 6 #defi

HDU 4027(线段树)

HDU4027 题意:操作指令为0时,对区间[x,y]之间的数字进行开平方:指令为1的时候,对区间[x,y]之间的数字求和并输出: 思路:线段树处理就OK了,但是64位内的数最多开8次平方就为1了(开始不信,试了试之后orz.......),所以在开平方的时候加一下限制条件使开平方操作提前结束没必要的操作就可以了,不然会超时. 代码中的这句:en - st + 1 == evil[rt]表示区间st到en中所有的数都是1,所以可以提前结束了. 代码: /* Time:2018/8/20 Auth

Can you answer these queries? HDU - 4027

Can you answer these querites? HDU - 4027 普通的线段树题,但是有一个问题是,区间更新时,因为必须更新每个点,才能更新区间,那么线段树更新就很慢了,无法使用lazy数组.有一个小技巧是当区间和等于区间长度时,那么说明已经到最好的情况了,不用再修改了.这一步简化后就可以过了 如果写线段树可以像喝水一样自然就好了 1 #include <iostream> 2 #include <cstring> 3 #include <vector>

V - Can you answer these queries? HDU - 4027 线段树

V - Can you answer these queries? HDU - 4027 这个题目开始没什么思路,因为不知道要怎么去区间更新这个开根号. 然后稍微看了一下题解,因为每一个数开根号最多开十几次就变成1了,所以就直接单点更新,但是这个可以剪枝. 如果碰到区间长度和区间大小相同就可以不用更新了. 我也是无语了,想到刚刚的做法之后很好写了, 不过要注意以下x,y 大小可能x>y, 这个bug如果不是之前看题解的时候瞄到了,我可能找不出来了. 因为我写对拍我肯定会保证x<y 的,还是就是