[HDOJ4027]Can you answer these queries?(线段树,特殊成段更新,成段查询)

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

RT,该题要求每次更新是更新所有节点,分别求平方根,查询是求和。昨晚思前想后找有没有一个数学上的开平方的和等于和的开平方之类的规律。但是想了想发现这不就是小的时候,如果你这么想那老师就会骂死你的那个- -!

所以显然这个题是无法按套路成段更新了,懒惰标记也是没有用了,我们应该去按照区间更新每一个节点。结果TLE了一发,这说明这题不是这么搞,一定还有规律的。注意到题目给数据规模是2^63以及题目红字所述:开根号全都取下整,除了考虑用longlong以外,我们其实还可以想一下对一个longlong的数据开平方,最终都会变成1。那么在更新这个节点至1的那次update里,更新结束后一定会从叶子rt向上更新父亲,如果rt的兄弟节点也是1,那么说明rt的父亲已经不再需要更新了(因为1开平方还是1),这时候rt的父亲存的结果是1+1=2。也就是(rt+1-rt+1)。推广到更高的节点,换成区间来表示就是(r-l+1)。我们遇到这种节点就不需要更新了。

特别需要注意的是题目中x和y的大小…会出现x>y的情况……以及,每个case最后都要有一个额外的\n…………(PE到死WA到死)

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <iomanip>
 4 #include <cstring>
 5 #include <climits>
 6 #include <complex>
 7 #include <fstream>
 8 #include <cassert>
 9 #include <cstdio>
10 #include <bitset>
11 #include <vector>
12 #include <deque>
13 #include <queue>
14 #include <stack>
15 #include <ctime>
16 #include <set>
17 #include <map>
18 #include <cmath>
19
20 using namespace std;
21
22 #define fr first
23 #define sc second
24 #define pb(a) push_back(a)
25 #define Rint(a) scanf("%d", &a)
26 #define Rll(a) scanf("%I64d", &a)
27 #define Rs(a) scanf("%s", a)
28 #define FRead() freopen("in", "r", stdin)
29 #define FWrite() freopen("out", "w", stdout)
30 #define Rep(i, len) for(LL i = 0; i < (len); i++)
31 #define For(i, a, len) for(LL i = (a); i < (len); i++)
32 #define Cls(a) memset((a), 0, sizeof(a))
33 #define Full(a) memset((a), 0x7f7f, sizeof(a))
34
35 typedef long long LL;
36 #define lrt rt << 1
37 #define rrt rt << 1 | 1
38 const LL maxn = 100100;
39 LL sum[maxn<<2];
40 LL n, q;
41
42 void pushUP(LL rt) {
43     sum[rt] = sum[lrt] + sum[rrt];
44 }
45
46 void build(LL l, LL r, LL rt) {
47     if(l == r) {
48         Rll(sum[rt]);
49         return;
50     }
51     LL m = (l + r) >> 1;
52     build(l, m, lrt);
53     build(m+1, r, rrt);
54     pushUP(rt);
55 }
56
57 void update(LL L, LL R, LL l, LL r, LL rt) {
58     if(sum[rt] == r - l + 1) return;
59     if(l == r) {
60         sum[rt] = LL(double(sqrt(sum[rt])));
61         return;
62     }
63     LL m = (l + r) >> 1;
64     if(m >= L) update(L, R, l, m, lrt);
65     if(m < R) update(L,R, m+1, r, rrt);
66     pushUP(rt);
67 }
68
69 LL query(LL L, LL R, LL l, LL r, LL rt) {
70     if(l >= L && R >= r) return sum[rt];
71     LL m = (l + r) >> 1;
72     LL ret = 0;
73     if(m >= L) ret += query(L, R, l, m, lrt);
74     if(m < R) ret += query(L, R, m+1, r, rrt);
75     return ret;
76 }
77
78 int main() {
79     // FRead();
80     LL orz = 1;
81     LL a, b, c;
82     while(~Rll(n)) {
83         Cls(sum);
84         printf("Case #%I64d:\n", orz++);
85         build(1, n, 1);
86         Rll(q);
87         while(q--) {
88             Rll(a); Rll(b); Rll(c);
89             if(b > c) swap(b, c);
90             if(a == 0) update(b, c, 1, n, 1);
91             if(a == 1) cout << query(b, c, 1, n, 1) << endl;
92         }
93         printf("\n");
94     }
95     return 0;
96 }
时间: 2024-08-23 05:57:21

[HDOJ4027]Can you answer these queries?(线段树,特殊成段更新,成段查询)的相关文章

HDU4027 Can you answer these queries 线段树区间求和+剪枝

给了你n,然后n个数字在一个数组中,接下来m个询问,每个询问三个数字 t,x,y,若t==0,那么修改区间[x,y]的每一个值,变为原来每个位置上的数 开根号取整,若t==1,那么对区间[x,y]求和 由于n,m,很大,所以树状数组铁定超时,若直接用线段树来做区间修改,那么也是超时,这类题目没别的方法了,静心剪枝,发现题目给的数据范围为2^63,有没有发现,2^63开根号 绝对不需要开10次,就能到1,到1以后就不需要再开了,意思就是若有某个区间[x,y]每一个点的值都为1时,这一段区间事实上是

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

hdu4027-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): 8330    Accepted Submission(s): 1904 Problem Description A lot of battleships of evil are arranged in a line before

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): 9216    Accepted Submission(s): 2106 Problem Description A lot of battleships of evil are arranged in a line before

hdu 4027 Can you answer these queries? 线段树区间开根号,区间求和

Can you answer these queries? Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5195 Description A lot of battleships of evil are arranged in a line before the battle. Our commander decides to use our secret weapo

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

Problem Description A lot of battleships of evil are arranged in a line before the battle. Our commander decides to use our secret weapon to eliminate the battleships. Each of the battleships can be marked a value of endurance. For every attack of ou

HDU4027Can 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): 8674 Accepted Submission(s): 1971 Problem Description A lot of battleships of evil are arranged in a line before the b

HDU 4027 Can you answer these queries?(线段树 区间不等更新)

题意  输入n个数  然后有两种操作   输入0时将给定区间所有数都变为自己的开方   输入1输出给定区间所有数的和 虽然是区间更新  但每个点更新的不一样  因此只能对单点进行更新  其实一个点最多被更新7次  2^64开平方7次后就变为1了  如果某个区间的数都变为了1  那么对这个区间的开方就不用考虑了   另外要注意给你的区间可能是反的 #include <bits/stdc++.h> #define lc p<<1,s,mid #define rc p<<1|