【樹狀數組】NYOJ-116士兵殺敵(二)

   

題目鏈接:http://acm.nyist.net/JudgeOnline/problem.php?pid=116


根據題意可知該題與士兵殺敵(一)不同,可以用樹狀數組來解這題,先來解釋一下樹狀數組


如圖:


可以得到:

C1 = A1
C2 = A1 + A2
C3 = A3
C4 = A1 + A2 + A3 + A4
C5 = A5
C6 = A5 + A6
C7 = A7
C8 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8
...
這裏有一個的性質:
設節點編號爲x,那麼這個節點管轄的區間爲2^k(其中k爲x二進制末尾0的個數)個元素。因爲這個區間最後一個元素必然爲Ax,
所以很明顯:Cn = A(n – 2^k + 1) + ... + An
算這個2^k有一個快捷的辦法,定義一個函數如下即可:
1
2
3
int lowbit(int x){
return x&(x^(x–1));
}
利用機器補碼特性,也可以寫成:
1
2
3
int lowbit(int x){
return x&-x;
}
當想要查詢一個SUM(n)(求a[n]的和),可以依據如下算法即可:
step1: 令sum = 0,轉第二步;
step2: 假如n <= 0,算法結束,返回sum值,否則sum = sum + Cn,轉第三步;
step3: 令n = n – lowbit(n),轉第二步。
可以看出,這個算法就是將這一個個區間的和全部加起來,爲什麼是效率是log(n)的呢?以下給出證明:
n = n – lowbit(n)這一步實際上等價於將n的二進制的最後一個1減去。而n的二進制裏最多有log(n)個1,所以查詢效率是log(n)的。
那麼修改呢,修改一個節點,必須修改其所有祖先,最壞情況下爲修改第一個元素,最多有log(n)的祖先。
所以修改算法如下(給某個結點i加上x):
step1: 當i > n時,算法結束,否則轉第二步;
step2: Ci = Ci + x, i = i + lowbit(i)轉第一步。
i = i +lowbit(i)這個過程實際上也只是一個把末尾1補爲0的過程。
對於數組求和來說樹狀數組簡直太快了!

修改操作

1
2
3
4
5
6
7
8
void add(int k,int num)  
{  
    while(k<=n)  
    {  
        tree[k]+=num;  
        k+=k&-k;  
    }  
}  

查詢操作

1
2
3
4
5
6
7
8
9
10
int read(int k)//1~k的區間和  
{  
    int sum=0;  
    while(k)  
    {  
        sum+=tree[k];  
        k-=k&-k;  
    }  
    return sum;  
}  

題目源碼:
#include<stdio.h>
int N, M, T[1000001];
//求k中有多少個能被2的多少次冪整除的,即2^k,也就是樹狀數組的作用域
int lowbit(int k) { 
  return k & (k ^ (k - 1));  //利用機器補碼特性也可以這樣寫 k & (-k);
}
void add(int k, int num) { //添加新值到樹狀數組中
  while(k <= N) {
    T[k] += num;
    k += lowbit(k);
  }
}
int sum(int k) { //前k個數的和 
  int sum = 0; 
  while(k) {
    sum += T[k];
    k -= lowbit(k);
  }
  return sum;
}
int main() {
  int a, m, n, I, A;
  char str[5];
  scanf("%d%d", &N, &M);
  for(int i = 1; i <= N; i++) {
    scanf("%d", &a); 
    add(i, a);
  }
  while(M--) {
    scanf("%s", str);
    if(str[0] == 'Q') {
      scanf("%d%d", &m, &n);      
      printf("%d\n", sum(n) - sum(m-1));         
    }
    else {
      scanf("%d%d", &I, &A);    
      add(I, A);
    }
  }
}     




發佈了23 篇原創文章 · 獲贊 14 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章