這篇主要來講一講樹狀陣列的區間修改
因為乙個乙個點改,毫無疑問耗時太長
所以,機智的人類yy出了用差分來表示陣列
為了便於理解,簡單一點陣列:a[1]=0, a[2]=0, a[3]=0, a[4]=0, a[5]=0, a[6]=0 ,a[7]=0, a[8]=0, a[9]=0
用差分思想,delta[x]表示a[x]-a[x-1]
顯然,一開始delta=0
我們先計算出前n項和來
然後別眨眼,下面就是見證奇蹟的時刻!
有個分界線顯得正式一點
我們要把a[3]到a[6]整段提高3個單位長度,就讓delta[3]+=3, delta[7]-=3
想象成階梯,一端抬起,另一端就壓下去。(自行腦補)
那麼現在的a[x]+=delta[1]+delta[2]+……+delta[x-1]+delta[x]
我現在要得到前7項的和,s[7]+=每一項應該加的差分
暨s[7]+=(delta[1])+(delta[1]+delta[2])+(delta[1])+delta[2]+delta[3])+……+(delta[1]+delta[2]+delta[3]+delta[4]+delta[5]+delta[6]+delta[7])
我還是畫個圖吧(為了方便說明只畫差分的)
顯然搬過磚的都知道,這個磚不好搬,因為它不方
那我們就把它變方來
(為什麼那麼醜,因為我不會畫畫以及懶)
額妹子!現在就好表示這堆磚了!!!!!!!!!
(7+1)(∑delta【1~7】)-(delta*1+delta*2+……+delta*7) (注意是7+1,不是7!!!!!!!!!)
後面的delta【n】*n很難看是不是?
那就表示成deltai【】
定義deltai【i】=delta【i】*i
顯然因為要大量求和,所以我們把deltai和delta維護成樹狀陣列
那麼
1 // 修改:把[l, r]區間均加上x
2 update(delta, l, x);
3 update(delta, r+1, -x);
4 update(deltai, l, x * l);
5 update(deltai, r+1, -x * (r+1));
// 查詢:[l, r]區間和是不是很神奇?long long suml = s[l - 1] + l * query(delta, l - 1) - query(deltai, l - 1);
long long sumr = s[r] + (r + 1) * query(delta, r) - query(deltai, r);
ans=sumr - suml;
#include#include#include#include#define lowbit(i) (i&-i)感謝typedef long long ll;
using namespace std;
const int n = 500005;
int n,m;
ll sum[n];
ll delta[n],deltai[n];
ll query(ll *p,int pos)
return ans;
}void updata(ll *p,int pos,int x)
}int main()
else
}return 0;
}
「每天心塞一點點」的部落格(我喜歡這個名字)
樹狀陣列 高階篇 區間修改,區間查詢
單點更新,區間查詢 我們知道,樹狀陣列最基本的功能是 單點更新,區間查詢 如下 int lowbit int x void add int x,int val int ask int x return res 區間更新,單點查詢 通過 單點更新,區間查詢 功能 差分的思想,我們實現了 區間更新,單點...
樹狀陣列區間修改
有時,我們要支援區間修改,區間查詢。線段樹可以做到。但是樹狀陣列更好寫。1d的情況 設 b i a i a i 1 則 a i b 1 b i a 1 a l b 1 b 1 b 2 b 1 b l a 1 a l l b 1 l 1 b 2 b l sum l i 1 b i 如果我們維護 b i...
樹狀陣列 小白篇(1)
身為一名弱省oier中的mengbier,簡單講一下我是怎麼學會基礎的樹狀陣列的 不算華麗的分割線 主要用於查詢任意一段資料中的所有元素之和。經過簡單修改可以在log n 的複雜度下進行範圍修改。也就是說你通過一系列神奇的操作可以實現在乙個數列中,修改其中一項ax的值 還可以是一段 並求出前n項和 ...