程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 習題: codevs 2492 上帝造題的七分鐘2 解題報告,codevs2492

習題: codevs 2492 上帝造題的七分鐘2 解題報告,codevs2492

編輯:C++入門知識

習題: codevs 2492 上帝造題的七分鐘2 解題報告,codevs2492


這道題是受到大犇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 }

這次解題報告就完結啦,蒟蒻一般是在每周的星期三晚和星期天晚發解題報告,大家就不要在其他時間翻我的博客啦。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved