樹狀陣列天生用來動態維護陣列字首和,其特點是每次更新乙個元素的值,查詢只能查陣列的字首和,
但這個題目求的是某一區間的陣列和,而且要支援批量更新某一區間內元素的值,怎麼辦呢?實際上,
還是可以把問題轉化為求陣列的字首和。
首先,看更新操作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
這其實就是三個陣列org[i], delta[i]和delta[i]*i的字首和,org[i]的字首和保持不變,事先就可以求出來,delta[i]和
delta[i]*i的字首和是不斷變化的,可以用兩個樹狀陣列來維護。
#include #include #include using namespace std;
#define maxn 100005
#define lowbit(x) (x&-x)
#define ll __int64
ll a[maxn], b[maxn], c[maxn], sum[maxn], n;
void add(ll a, ll x, ll d)
}ll sum(ll a, ll x)
return sum;
}int main()
else}}
return 0;
}
樹狀陣列區間更新 單點查詢
設a陣列表示原來的區間 c i a i a i 1 這樣可以看出 a i sum c 1 c 2 c i 例如 a 1 3 4 2 6 8 c 1 2 1 2 4 2 樹狀陣列維護的是c陣列 當把a 3,5 每個數都加2時,我們看c陣列,由於c陣列維護的是相鄰區間的差值,所以c 3 2 因為區間 3...
樹狀陣列點更新,區間更新理解
對於乙個數列a1a2a3 an,要求支援兩種操作 1.查詢 x,y 區間的區間和 2.把 x,y 區間每個元素加val 事實上線段樹也可以解決這樣的問題,用上一點lazy的思想,每次只更新小區間的區間和,查詢的時候加上祖先節點的影響就可以了。我們用樹狀陣列也可以解決這樣的問題,並且效率會更高一些,複...
樹狀陣列區間更新 區間查詢 單點查詢
為了更好地使用複雜度比線段樹更加優化的樹狀陣列,所以必須實現樹狀陣列的區間更新 樹狀陣列時間複雜度為o mlogn 實際用的時候優於線段樹,且寫得少。引入差分陣列,假設初始資料陣列為a,另a 0 0 設要維護的差分陣列為 d i a i a i 1 進一步可知 a i d 1 d 2 d i 即前i...