HDU 4027【线段树+求和+动态改变区间各数的值】

题意:

首先给出1-N个数,然后有两种操作。

第一种操作: 0 x y, 表示将x,y之间的数全部开根号。

第二种操作: 1 x y, 表示求x,y之间的全部数之和。

解题思路:

看到题目,应很自然想到了线段树和数状数组,两种结构都能快速求出区间之和。但两者的优点不尽相同,前者在维护方面更自由一点,后者能更快速维护和求和。

这题的解题突破点是:当一个数开根后得到1或0时,此后此值不会再改变。利用这个特点,设置一个变量表示x,y区间是否全部为1或0,如果为真,则在这个区间上的第一种操作直接忽略。

ContractedBlock.gif ExpandedBlockStart.gif View Code
  1 #include <iostream>
2 #include <cstdio>
3 #include <cmath>
4
5 using namespace std;
6
7 const int MAX = 100000 + 10;
8 typedef long long llint;
9 struct TTree
10 {
11 int left;
12 int right;
13 llint sum;
14 bool flag;
15 }Tree[MAX * 10];
16
17 void build(int left, int right, int num)
18 {
19 Tree[num].left = left;
20 Tree[num].right = right;
21 Tree[num].sum = 0;
22 Tree[num].flag = false;
23 if(left == right)
24 return;
25 int mid = (left + right) >> 1;
26 build(left, mid, num * 2);
27 build(mid + 1, right, num * 2 + 1);
28 }
29
30 void insert(int pos, llint val, int num)
31 {
32 if(Tree[num].left == Tree[num].right)
33 {
34 Tree[num].sum = val;
35 return;
36 }
37 int mid = (Tree[num].left + Tree[num].right) >> 1;
38 if(pos <= mid)
39 insert(pos, val, num * 2);
40 else
41 insert(pos, val, num * 2 + 1);
42 Tree[num].sum = Tree[num * 2].sum + Tree[num * 2 + 1].sum;
43 }
44
45 llint getSum(int from, int to, int num)
46 {
47 if(Tree[num].right < from || Tree[num].left > to)
48 return 0;
49 if(Tree[num].left >= from && Tree[num].right <= to)
50 return Tree[num].sum;
51 return getSum(from, to, num * 2) + getSum(from, to, num * 2 + 1);
52 }
53
54 void decrease(int from, int to, int num)
55 {
56 if(Tree[num].flag || to < Tree[num].left || from > Tree[num].right)
57 return;
58 if(Tree[num].left == Tree[num].right)
59 {
60 if((Tree[num].sum = (llint)(sqrt((double)Tree[num].sum)) + 1e-8) <= 1LL)
61 Tree[num].flag = true;
62 return;
63 }
64 decrease(from, to, num * 2);
65 decrease(from, to, num * 2 + 1);
66 Tree[num].sum = Tree[num * 2].sum + Tree[num * 2 + 1].sum;
67 Tree[num].flag = Tree[num * 2].flag && Tree[num * 2 + 1].flag;
68 }
69
70 int main()
71 {
72 freopen("in.txt","r",stdin);
73 int N, Q;
74 int op, f, t;
75 llint endurance;
76 int T = 1;
77 while(scanf("%d", &N) == 1)
78 {
79 printf("Case #%d:\n", T++);
80 build(1, N, 1);
81 for(int i = 1; i <= N; ++i)
82 {
83 scanf("%I64d", &endurance);
84 insert(i, endurance, 1);
85 }
86 scanf("%d", &Q);
87 for(int j = 1; j <= Q; ++j)
88 {
89 scanf("%d%d%d", &op, &f, &t);
90 if(f > t)
91 {
92 int temp = f;
93 f = t;
94 t = temp;
95 }
96 if(op == 0)
97 decrease(f, t, 1);
98 else
99 printf("%I64d\n", getSum(f, t, 1));
100 }
101 printf("\n");
102 }
103 return 0;
104 }

转载于:https://www.cnblogs.com/Kenfly/archive/2011/09/14/2175339.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值