上一篇講的是區間求和,這一篇講區間求最值。
首先,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 < i或l > i,c[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 }
樹狀數組區間求和——
http://www.cnblogs.com/mypride/p/5001858.html
