【進階——樹狀數組】 區間求最值


上一篇講的是區間求和,這一篇講區間求最值。

首先,a[]數組仍然是保存原始數據。但是c[]數組變了,c[i]將會保存從a[1]a[i]的最值。

初始化c[]

當我們輸入a[i]時,c[i]需要需要向前依次枚舉被c[i]所包含的c[]數組。比如,當i == 8時,需要向前依次枚舉c[7], c[6], c[4],取a[8]與這幾個c[]中的最值保存在c[8]中。找到c[]的規律了沒有?依次是i-1, i-2, i-4...

 1 void Init()
 2 {
 3     int  y;
 4     memset(c, 0, sizeof(c));
 5     for(int i = 1; i <= n; i++)
 6     {
 7         scanf("%d", &y);
 8         a[i] = y;
 9         c[i] = y;
10         for(int j = 1; j <lowbit(i); j <<= 1)           //需要比較的c[]
11             c[i] = c[i] > c[i-j] ? c[i] : c[i-j];
12     }
13 }

可以看出,每輸入一個a[i],處理c[i]的時間復雜度為log2(n),輸入n個,初始化的時間復雜度就是n*log2(n)

 

修改c[]

我們改變了一個a[i],那么就需要修改所有與a[i],相關的c[]。修改每個的c[]的方法可以用上面初始化的方法,而需要修改的c[]可以用區間求和里的一段代碼確定。

 

 1 void Maxn(int x, int y)
 2 {
 3     a[x] = y;
 4     for(int i = x; i <= n; i += lowbit(i))              //需要修改的c[]
 5     {
 6         c[i] = y;
 7         for(int j = 1; j < lowbit(i); j <<= 1)          //修改時需要比較的c[]
 8         {
 9             c[i] = c[i] > c[i-j] ? c[i] : c[i-j];
10         }
11     }
12 }

 

每次修改的時間復雜度近似為log2(n)*log2(n)

 

查詢:

查詢從a[i]a[j]之間的最值(i <= j)。我們不能直接查看c[j],因為也許c[j]中包含的區間[l, r]l < il > ic[j]不能恰好包含區間[i, j]

因此,當l < i時,我們就取a[j]與當前已經取到的最值比較,如果a[j]滿足取代條件,就用a[j]取代當前最值。

l >= i,我們取c[j]與當前最值比較,如果c[j],滿足取代條件,就用c[j]取代當前最值。

l == i時,比較結束。

 

 1 void Query(int l, int r)
 2 {
 3     int ans = 0;
 4     while(1)
 5     {
 6         ans = ans > a[r] ? ans : a[r];
 7         if(r == l) break;
 8         for(r -= 1; r-l >= lowbit(r); r -= lowbit(r))
 9             ans = ans > c[r] ? ans : c[r];
10     }
11     printf("%d\n", ans);
12 }

 

時間復雜度近似為log2(n)

 

 1 #include <cstdio>
 2 #include <cmath>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 const int N = 200010;
 8 
 9 int a[N], c[N];
10 int t, n, m;
11 
12 int lowbit(int x)
13 {
14     return x&(-x);
15 }
16 
17 void Maxn(int x, int y)
18 {
19     a[x] = y;
20     for(int i = x; i <= n; i += lowbit(i))              //需要修改的c[]
21     {
22         c[i] = y;
23         for(int j = 1; j < lowbit(i); j <<= 1)          //修改時需要比較的c[]
24         {
25             c[i] = c[i] > c[i-j] ? c[i] : c[i-j];
26         }
27     }
28 }
29 
30 void Init()
31 {
32     int  y;
33     memset(c, 0, sizeof(c));
34     for(int i = 1; i <= n; i++)
35     {
36         scanf("%d", &y);
37         a[i] = y;
38         c[i] = y;
39         for(int j = 1; j <lowbit(i); j <<= 1)           //需要比較的c[]
40             c[i] = c[i] > c[i-j] ? c[i] : c[i-j];
41     }
42 }
43 
44 void Query(int l, int r)
45 {
46     int ans = 0;
47     while(1)
48     {
49         ans = ans > a[r] ? ans : a[r];
50         if(r == l) break;
51         for(r -= 1; r-l >= lowbit(r); r -= lowbit(r))
52             ans = ans > c[r] ? ans : c[r];
53     }
54     printf("%d\n", ans);
55 }
56 
57 void Work()
58 {
59     char s[2];
60     int x, y;
61     for(int i = 1; i <= m; i++)
62     {
63         scanf("%s%d%d", s, &x, &y);
64         if(s[0] == 'U') Maxn(x, y);
65         else if(s[0] == 'Q') Query(x, y);
66     }
67 }
68 
69 int main()
70 {
71     //freopen("test.in", "r", stdin);
72     while(~scanf("%d%d", &n, &m))
73     {
74         Init();
75         Work();
76     }
77 }
mod

 

樹狀數組區間求和——
http://www.cnblogs.com/mypride/p/5001858.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM