樹狀數組是一個思想很巧妙的算法。
樹狀數組主要是求動態連續和、查詢等問題
先理解lowbit(i) , i是指數組中的位置(從1開始) , lowbit(i) 是i的二進制表達式中最右邊的1所對應的值 , 也就是說lowbit(i) = i&(-i)
假設a[i]存儲的是樹 , c[i]是表示a[i] + a[i-1].......+a[i-lowbit(i)] , 那麼這時 , 我們要求數組a中前 i 個數和 (a[i]+a[i-1].....+a[1]),我們只需要這麼求:
int sum_tree_shuzu(int i) { int sum = 0; while(i>0) { sum += c[i]; i -= lowbit(i); } return sum; }
當我們改變了數組a中的某個數時 , 應該怎麼來改變數組c中的值呢。
我們假設改變:a[i] = a[i]+d;
這時我們只需要改變數組 c 中和 a[i] 相關的值。
void add_tree_shuzu(int i , int d) { while(i <= n) { b[i] += d; i += lowbit(i); } }
下面說一下例題:poj 3928
這個題目的關鍵點:
1、每個隊員的能力值都不一樣 , 就說沒有想等的能力值
2、我們只需要對裁判遍歷。
代碼:
#include#include #include #include using namespace std; int a[20010] , b[20010] , c[20010]; int n; bool cmp(int i , int j) { return a[i] <= a[j]; } inline int lowbit(int y) { return y&(-y); } int sum_tree_shuzu(int y) { int sum = 0; while(y>0) { sum += b[y]; y -= lowbit(y); } return sum; } void add_tree_shuzu(int i , int x) { while(i <= n) { b[i] += x; i += lowbit(i); } } int main() { int t; scanf("%d" , &t); while(t--) { scanf("%d" , &n); int i , x , j; memset(b , 0 , sizeof(b)); for(i = 1; i <= n; i++) { scanf("%d" , &a[i]); c[i] = i; } sort(c+1 , c+n+1, cmp); //對隊員的能力值進行排序, add_tree_shuzu(c[1] , 1); __int64 sum = 0; for(i = 2; i < n; i++) { x = sum_tree_shuzu(c[i]); sum += x*(n-c[i]-i+x+1) + (i-1-x)*(c[i]-1-x);//裁判住在c[i]的位置,那麼有i-1個隊員住在裁判前面,n-i個隊員住在裁判後面 add_tree_shuzu(c[i] , 1); } printf("%I64d\n" , sum); } return 0; }