基礎演算法-差分與字首和
原創 acm algorithm acm演算法 4月23日
差分與字首和
首先要說明的是這兩種方法都是優化了對陣列進行操作的時間複雜度,我們先來看兩個問題。
問題1:已知乙個陣列a的長度為n(n<=1e6),問陣列a從i到j這個區間所有數的和的為多少(一共有k次詢問,k<=1e6)?
問題2:已知乙個陣列a的長度為n(n<=1e6),對陣列a從i到j這個區間加或者減乙個定值w(一共有k次操作,k<=1e6)。問操作後的陣列中每個數的值為多少?
字首和對於問題1,使用暴力的時間複雜度為o(n*k),顯然這樣是行不通的。有沒有更好的解決方式呢?答案是有的。
什麼是字首和?有兩個陣列arr與brr,對於任意的角標i,陣列brr[i]=arr[1]+arr[2]+ … +arr[i],即:
brr[1]=arr[1];
brr[2]=arr[1]+arr[2];
brr[3]=arr[1]+arr[2]+arr[3];
…brr[i-1]=arr[1]+arr[2]+…+arr[i-1];
brr[i]=arr[1]+arr[2]+…+arr[i-1]+arr[i];
陣列arr中從i到j的所有數的和=brr[j]-brr[i-1].這樣的方法叫字首和,陣列brr為陣列arr的字首和陣列,並且我們通過上面的式子發現brr[i]=brr[i-1]+arr[i],所以我們同時縮短求字首和的時間複雜度,故此時解決問題1的時間複雜度為o(n+m)
給出解決問題1的**
#include
using namespace std;
const int mi=1e6+10;
int arr[mi],brr[mi];
int main()
for(int i=1;i<=n;i++)//求字首和
int k;//獲取k
while(k–)}差分
對於問題2,我們假設操作的陣列是上面的brr,經過分析,如果對arr[i]加上乙個定值w,那麼從brr[i]到brr[n]的每乙個數都會加上w,然後對arr[j+1]減去w,這時brr陣列相當於從i到j加上w。問題2就這樣解決了,其中arr[i]=brr[i]-brr[i-1],arr為brr的差分陣列。附上問題2的解題**
#include
using namespace std;
const int mi=1e6+10;
int arr[mi],brr[mi];
int main()
for(int i=1;i<=n;i++)//求差分
int k;//獲取k
while(k–)
for(int i=1;i<=n;i++)
}字首和與差分的關係
假設陣列a是陣列b的字首和陣列,那麼陣列b就是陣列a的差分陣列。
字首和是解決對陣列的區間查詢多,修改少的問題。
差分是解決對陣列的區間修改的資料相同,並且修改次數多,但查詢少的問題。
如果遇到對陣列區間查詢多,修改也多的情況怎麼辦?不著急,有一種叫做線段樹的資料結構會來解決這種問題。不過需要強調的是線段樹的時間複雜度為o(nlogn),而字首和與差分的時間複雜度為o(n)。
偷偷告訴你,這是一道差分題。
關鍵字差分、字首和
字首與差分
2.板子 2.2 差分 3.板子 定義 s n i 1na i sum na i i 1n a i 遞推關係 s i a i s i 1 區間求和 i lra i s r s l 1 sum ra i s r s l 1 i lr a i s r s l 1 定義 存在兩個陣列a a1,a2,a3,...
字首和 差分與樹上差分
1.1 字首和 字首和可以通過對乙個序列進行o n 的預處理後,在o 1 時間內求出任意乙個子串行的和。1.2 差分 可以用於求解多次區間修改與區間詢問的題型,例如多次次給 l r 內所有數 val,就可以用差分以及字首和來優化。區間操作o 1 區間詢問o n 處理,o 1 查詢。1.3 樹上差分 ...
字首和與差分
數列的字首和 sum i 表示a 1 a i 的和 用處1 求i j的和sum j sum i 1 用處2 區間修改。設定乙個change陣列。當區間 i,j 上要加k時,我們令change i k,令change j 1 k。如果我們對change陣列求字首和的話,字首和sum change i ...