差分
區間加:把數組a[l]到a[r]都加上k,這種操作稱為區間加。
如果一般朴素的想法應該是下面這樣的:
int a[10005],l,r,k; for(int i=l;i<=r;i++){ a[i]+=k; }
但可以發現如果是l-r非常大的話,這個操作執行的次數又很多,那時間復雜度會很高(其實是我不會算)
所以我們通過引入差分的概念,簡化這個問題。
差分:差分即相鄰兩個數的差。我們用一個數組p存儲a的差分,那么p是a的差分數組,即pi=ai-ai-1 。
這張圖可以幫助更好地理解差分的概念
那么通過差分,如果繼續做區間加操作的話,只需要像下面這樣。
首先是查分數組的初始化:
int p[10],a[10]={0,1,2,3,90,5,6,7,8,9}; //p是a的差分數組 for(int i=1;i<=9;i++){ p[i]=a[i]-a[i-1]; cout<<p[i]<<" "; }
這段代碼會輸出
輸出: 1 1 1 87 -85 1 1 1 1
那么我們現在就可以進行區間加操作了,代碼如下:
int p[10],a[10]={0,1,2,3,90,5,6,7,8,9}; void pl(int l,int r,int k){ //操作:在[l,r]上加 k p[l]+=k,p[r+1]-=k; //注意是 r+1 !!! return; }
那么當我們要輸出數組a的某一個元素要怎么辦呢
很簡單,通過差分數組p和原來的數組a“倒推”出a[i],代碼實現如下
void get_a(){ for(int i=1;i<=9;i++){ a[i]=p[i]+a[i-1]; } }
前綴和
前綴和其實就是用一個數組s來記錄數組a前i項的和,有點類似數列的求和。也可用來求區間和,如求數組a在區間[l,r]的和,就可以s[r]-s[l-1](注意要減1哦!!!!!)
我們在輸入a數組時可以預處理一下,代碼如下。
int a[11],s[11]; a[0]=0,s[0]=a[0]; for(int i=1;i<=10;i++){ a[i]=i*i; s[i]=s[i-1]+a[i]; cout<<a[i]<<" "; } cout<<endl; for(int i=1;i<=10;i++){ cout<<s[i]<<" "; } cout<<endl;
輸出結果如下:
1 4 9 16 25 36 49 64 81 100 1 5 14 30 55 91 140 204 285 385
那么區間[l,r]的和就是下面這樣:
int qjh(int l,int r){ return s[r]-s[l-1]; } cout<<qjh(3,6);
這里會輸出
86