士兵殺敵(一) 陣列是固定的,所以可以用乙個sum陣列來儲存每個元素的和就行,但是不能每次都加,因為那樣會超時,查詢次數太多。但是這個士兵殺敵(二)就不能用那個方法來解了,因為這個是動態的,中間元素的值可能會變化,所以引出乙個新的東西來。剛開始想了一下,實在是沒有想到方法,就去討論區看了看,一看好像都說用樹狀陣列,就去找樹狀陣列的用法。
先上圖,看著**釋容易理解點。
陣列a是原陣列中的元素,陣列c是樹狀陣列中的元素,圖中c陣列的元素組成為a中的某些元素之和,這些元素的個數取決於它的下標能被多少個2整除,像c[1] = a[1]; c[2] = a[1] + a[2]; c[3] = a[3]; c[4] = a[1] + a[2] + a[3] + [4] = c[2] + c[3]; ……這些個數可以寫乙個通式c[i] = a[n - 2^k + 1] + ……+a[i]; 其中k為 i 的二進位制中從右往左數的 0 的個數 ,就像6有乙個, 6可以寫成 2 × 3, 所以c[6] = a[5] + a[6]; 所以可以定義乙個函式來求這個數.
6的二進位制為0110
5的二進位制為0101
6^5 = 0011
6&(6^5) = 0010 = 十進位制中的2
所以函式可以這麼寫
int lowbit(int n)//也可以寫成求n中有多少個能被2的多少次冪整除的,即2^k, 也就是樹狀陣列的作用域
int lowbit(int n)//更改乙個數的值, 就要更改次數在樹狀陣列中的所有祖先,不過這個時間複雜度是o(logn); 下面是更改值(新增殺敵數)的函式求n中有多少個能被2的多少次冪整除的,即2^k, 也就是樹狀陣列的作用域
void add(int pos, int num)//下面就是求和函式, 因為這種方法之所以快,是求他的最小樹根節點的和, 最小樹的個數為當前要求的n的二進位制中為1的個數,即展開式中能寫成不同2的冪指數的項數,新增新值到樹狀陣列中
}
例如: 15 = 2^3 + 2^2 + 2^1 + 2^0; 所以n = 15時, 最小數有四個,求和的時間複雜度為o(logn);
int sum(int n)//關鍵就是這三步, 這三步搞明白了,基本上就不成問題了,但是,當時按照 殺敵(一) 中的思維,還統計了乙個總數,那樣不會快,反而會慢,所以直接求就行,下面是完整的**求前n個數的和
return
sum;
}
1 #include 2 #include 34int tmp[1001000];5
intn, k;67
int lowbit(int n)//
求n中有多少個能被2的多少次冪整除的,即2^k, 也就是樹狀陣列的作用域811
12void add(int pos, int num)//
新增新值到樹狀陣列中
1319}20
21int sum(int n)//
求前n個數的和
2229
return
sum;30}
3132
intmain()
3342
for(int i = 0; i < k; i++)
4350
51return0;
52 }
nyoj 116 士兵殺敵(二) 樹狀陣列
時間限制 1000 ms 記憶體限制 65535 kb 難度 5 描述 南將軍手下有n個士兵,分別編號1到n,這些士兵的殺敵數都是已知的。小工是南將軍手下的軍師,南將軍經常想知道第m號到第n號士兵的總殺敵數,請你幫助小工來回答南將軍吧。南將軍的某次詢問之後士兵i可能又殺敵q人,之後南將軍再詢問的時候...
(樹狀陣列)NYOJ116 士兵殺敵(二)
傳送門 nyoj116 士兵殺敵 二 描述 南將軍手下有n個士兵,分別編號1到n,這些士兵的殺敵數都是已知的。小工是南將軍手下的軍師,南將軍經常想知道第m號到第n號士兵的總殺敵數,請你幫助小工來回答南將軍吧。南將軍的某次詢問之後士兵i可能又殺敵q人,之後南將軍再詢問的時候,需要考慮到新增的殺敵數。輸...
nyoj 116 士兵殺敵(二) 樹狀陣列
時間限制 1000 ms 記憶體限制 65535 kb 難度 5 描述南將軍手下有n個士兵,分別編號1到n,這些士兵的殺敵數都是已知的。小工是南將軍手下的軍師,南將軍經常想知道第m號到第n號士兵的總殺敵數,請你幫助小工來回答南將軍吧。南將軍的某次詢問之後士兵i可能又殺敵q人,之後南將軍再詢問的時候,...