題意:給你一個數列,每次詢問一個區間的和,或者每次將一個區間的所有元素都加上一個數
一 算法
樹狀數組天生用來動態維護數組前綴和,其特點是每次更新一個元素的值,查詢只能查數組的前綴和,
但這個題目求的是某一區間的數組和,而且要支持批量更新某一區間內元素的值,怎麼辦呢?實際上,
還是可以把問題轉化爲求數組的前綴和。
首先,看更新操作update(s, t, d)把區間A[s]...A[t]都增加d,我們引入一個數組delta[i],表示
A[i]...A[n]的共同增量,n是數組的大小。那麼update操作可以轉化爲:
1)令delta[s] = delta[s] + d,表示將A[s]...A[n]同時增加d,但這樣A[t+1]...A[n]就多加了d,所以
2)再令delta[t+1] = delta[t+1] - d,表示將A[t+1]...A[n]同時減d
然後來看查詢操作query(s, t),求A[s]...A[t]的區間和,轉化爲求前綴和,設sum[i] = A[1]+...+A[i],則
A[s]+...+A[t] = sum[t] - sum[s-1],
那麼前綴和sum[x]又如何求呢?它由兩部分組成,一是數組的原始和,二是該區間內的累計增量和, 把數組A的原始
值保存在數組org中,並且delta[i]對sum[x]的貢獻值爲delta[i]*(x+1-i),那麼
sum[x] = org[1]+...+org[x] + delta[1]*x + delta[2]*(x-1) + delta[3]*(x-2)+...+delta[x]*1
= org[1]+...+org[x] + segma(delta[i]*(x+1-i))
= segma(org[i]) + (x+1)*segma(delta[i]) - segma(delta[i]*i),1 <= i <= x
=segma(org[i]-delta[i]*i)+(x+1)*delta[i], i<=1<=x //by huicpc0207 修改 這裏就可以轉化爲兩個個數組
這其實就是三個數組org[i], delta[i]和delta[i]*i的前綴和,org[i]的前綴和保持不變,事先就可以求出來,delta[i]和
delta[i]*i的前綴和是不斷變化的,可以用兩個樹狀數組來維護。
樹狀數組的解法比樸素線段樹快很多,如果把long long變量改成__int64,然後用C提交的話,可以達到1047ms,
排在22名,但很奇怪,如果用long long變量,用gcc提交的話就要慢很多。