這道題是受到大犇MagHSK的啟發我才得以想出來的,蒟蒻覺得自己的代碼跟MagHSK大犇的代碼完全比不上,所以這裡蒟蒻就套用了MagHSK大犇的代碼(大家可以關注下我的博客,友情鏈接就是大犇MagHSK的博客,大神是山東省隊隊員,他的博客中的題的質量都比我高幾個檔次);
這是大神MagHSK的解釋:因為10^9頂多開5~6次方就成了1了(當然這裡的等於是向下取整的)因此對於修改操作,如果某一段不是1或不是0,就暴力修改,如果是1/0就不管他。修改完之後update一下就好了。
題目上說我們給出的是一個可修改(修改的規則就是對要修改的區間內每個數開平方)、可查詢(就是求一段區間上所有數字的和)的一個數列。
顯然我們直接暴力的效率是很低的,那麼我們就采取了線段樹——一種神奇的數據結構。
線段樹作為可修改可查詢的數據結構,基本操作就是點更新、區間更新和區間查詢(包括最小值、最大值和區間和)這裡因為是解題報告,所以就不跟大家講基本思路了,直接進入正題,基本思路和代碼板子請自己去看。
這裡因為是對區間內的數開平方,所以區間更新就有點不大好用了(主要是沒法直接標記區間然後開平方,這樣會計算錯誤),然後數據范圍也不算大,所以我們就考慮搜索線段樹上的每一個在需要update(更新)的區間的所有點進行開方點更新,然後再push_up(往上面推,求出每個線段樹上區間的和)上去。這樣就可以完成更新任務了。(push_up和change(update)函數代碼跟板子上不大一樣,all數組就是標記這個區間內的數還值不值得進行開平方操作,顯然如果這個區間內的和為1或者0的時候就不用開平方了,change的時候就可以省略了)。
區間查詢的操作就是套板子,這個沒什麼需要思考的。
還是那句老話,要先考慮自己寫,然後實在不會了再看題解,總是copy別人的代碼自己的水平肯定上升得很慢。
廢話不再說,上代碼。
1 #include <cstdio>
2 #include <algorithm>
3 #include <cmath>
4 using namespace std;
5 typedef long long LL;
6 const int INF = 1009999999;
7 int n;
8 LL sum[500005], A[500005];
9 bool all[500005];
10 void pu(int now) {
11 sum[now] = sum[now << 1] + sum[now << 1 | 1];
12 all[now] = all[now << 1] && all[now << 1 | 1];
13 }
14 void build(int now, int l, int r) {
15 if (l == r) {
16 sum[now] = A[l];
17 if (sum[now] == 1 || sum[now] == 0)
18 all[now] = true;
19 return;
20 }
21 int mid = (l + r) >> 1;
22 build(now << 1, l, mid);
23 build(now << 1 | 1, mid + 1, r);
24 pu(now);
25 }
26 LL query(int now, int l, int r, int ll, int rr) {
27 if (ll <= l && r <= rr) {
28 return sum[now];
29 }
30 int mid = (l + r) >> 1;
31 LL ret = 0;
32 if (ll <= mid) ret += query(now << 1, l, mid, ll, rr);
33 if (rr > mid) ret += query(now << 1 | 1, mid + 1, r, ll, rr);
34 return ret;
35 }
36 void change(int now, int l, int r, int ll, int rr) {
37 if (all[now]) {
38 return;
39 }
40 if (l == r) {
41 sum[now] = sqrt(sum[now]);
42 if (sum[now] == 1 || sum[now] == 0)
43 all[now] = true;
44 return;
45 }
46 int mid = (l + r) >> 1;
47 if (ll <= mid) change(now << 1, l, mid, ll, rr);
48 if (rr > mid) change(now << 1 | 1, mid + 1, r, ll, rr);
49 pu(now);
50 }
51 int main() {
52 scanf("%d", &n);
53 for (int i = 1; i <= n; ++i)
54 scanf("%lld", A+i);
55 build(1, 1, n);
56 int m, x, y, z;
57 scanf("%d", &m);
58 while (m--) {
59 scanf("%d%d%d", &x, &y, &z);
60 if (y > z) swap(y, z);
61 if (x==1) {
62 printf("%lld\n", query(1, 1, n, y, z));
63 } else {
64 change(1, 1, n, y, z);
65 }
66 }
67 return 0;
68 }
這次解題報告就完結啦,蒟蒻一般是在每周的星期三晚和星期天晚發解題報告,大家就不要在其他時間翻我的博客啦。