1首先從一維的開始,考慮最基礎的單點修改,區間查詢。樹狀陣列模板1:這個是最基礎的,就是定義的應用。
2再考慮區間修改,單點查詢。樹狀陣列模板2。
我們可以想到,在對一段區間\(\;[l,r]\;\)進行修改時,可以將\(\;[1,r]\;\)加上\(\;k\),將\(\;[1,l-1]\;\)減去\(\;k\;\)。但這樣修改,對於單點查詢來說,似乎不是那麼的方便,我們可能需要求出\(\;[1,x]\;\)和\(\;[1,x-1]\;\)的字首和,再做個差。好像...有點麻煩。
那麼有什麼更好的方法呢?——考慮差分。
我們定義\(\;d_i=a_i-a_,\;a_0=0\;\)。那麼每次修改,就只需要將\(\;d_l\;\)和\(\;d_\;\)進行修改,而單點查詢即為\(\;\sum\limits_^xd_i\)。直接進行字首和查詢即可。
3還有的就是區間修改,區間求和了。線段樹模板1。
我們跟著上面區間修改,單點查詢的思路來,還是考慮差分。
修改的話,如同上面一樣,只對差分陣列\(\;d_\;\)和\(\;d_r\;\)進行修改,但有些許變動。
我們來看乙個式子:
\[\sum\limits_^r\sum\limits_^id_j-\sum\limits_^\sum\limits_^id_j
\]這個式子前一半表示的是區間\(\;[1,r]\;\)的和,後一半是區間\(\;[1,l-1]\;\)的和,二者做差即為所求的區間\(\;[l,r]\;\)的和。
嘗試對其化簡。
我們先只考慮前一半,即\(\;\sum\limits_^r\sum\limits_^id_j\)。
發現\(\;d_1\;\)出現了\(\;r\;\)次,\(\;d_2\;\)出現了\(\;r-1\;\)次\(\;\ldots\)
\(d_x\;\)出現了\(\;r-x+1\;\)次。至此,我們發現式子可以變為:
\[\sum\limits_^rd_i\times (r-i+1)
\]展開可得:
\[(r+1)\times \sum\limits_^rd_i-\sum\limits_^rd_i\times i
\]最終我們只需開兩個樹狀陣列來維護\(\;d_i\;\)和\(\;d_i\times i\;\)即可。
修改:
il void add(int x,ll val)
il void real_add(int l,int r,int val)
查詢:
il ll ask(int x)
il ll real_ask(int l,int r)
4接下來考慮單點修改,區間查詢。二維樹狀陣列模板。
我們只需將一維擴充套件到二維,**只需進行一定的修改即可:
修改:
inline void add(int x,int y,int val)
查詢:
inline int ask(int x,int y)
5最後是區間修改,區間查詢。上帝造題的七分鐘。
回想一下,我們是怎麼進行一維的區間修改的——差分。差分陣列\(\;\sum\limits_^nd_i=a_i\;\)。再想一下差分陣列是如何求出來的。
我們來看兩個式子:
\[sum_i=sum_+a_i
\]\[d_i=a_i-a_
\]應該能發現什麼吧——差分陣列的計算有點像字首和計算的逆運算。所以,我們可以仿照二維陣列的字首和公式來推出二維陣列的差分公式。
\[sum_=sum_j}+sum_}-sum_}
\]\[d_=a_-a_j}-a_}+a_}
\]在回想一下,我們在進行一維陣列的差分修改時是如何修改的——再將其擴充套件到二維。
當我們要修改乙個二維區間 \(\;(x_1,y_1)\ \ (x_2,y_2)\;\) 所組成的矩形時,只需修改\(\;(x_1,y_1)\ \ (x_1,y_2+1)\ \ (x_2+1,y_1)\ \ (x_2+1,y_2+1)\;\)四個點。那麼,如何修改呢?
我們來看乙個式子:
\[\sum\limits_^x\sum\limits_^y\sum\limits_^i\sum\limits_^jd_
\]我們發現,\(\;d_\;\) 出現了\(\;x\times y\;\)次,\(\;d_\;\)出現了 \(\;x\times \;\)次\(\;\ldots\)
\(\;d_\;\)出現了\(\;\times \;\)次。
我們將式子展開,可得到
\[\sum\limits_^x\sum\limits_^y\times (x-i+1)\times (y-j+1)}
\]再次展開
\[^x\sum\limits_^yd}-^x\sum\limits_^y\times i}}-^x\sum\limits_^y\times j}}+^x\sum\limits_^y\times i\times j}}
\]那麼,我們就只需開四個樹狀陣列來分別維護\(d_\quad d_\times i\quad d\times j\quad d\times i\times j\)即可。
區間查詢就是\(\;sum_}-sum_}-sum_}+sum_}\)
完整**:
//二維樹狀陣列,區間修改,區間查詢
#includeusing namespace std;
const int maxn=2050;
#define neko puts("neko")
#define il inline
#define vocaloid(v) (v>='0'&&v<='9')
il int read()
while(vocaloid(v))
return x*flag;
}il int lowbit(int x)
int n,m,c1[maxn][maxn],c2[maxn][maxn],c3[maxn][maxn],c4[maxn][maxn];
char ch;int x1,x2,y1,y2,val;
il void add(int x,int y,int val) }
il void real_add(int x1,int y1,int x2,int y2,int val)
il int ask(int x,int y)
il int real_ask(int x1,int y1,int x2,int y2)
int main()
if(ch=='k')
}return 0;
}
lv1_kangdi——二維樹狀陣列總結及模板
fmj_123——luogu-p4514-二維樹狀陣列
十分感謝他們的部落格對我學習此內容的幫助。
二維樹狀陣列 學習筆記
前言 遇到二維的問題都很虛,而且樹狀陣列也不熟練 於是學了一發這個。以下所有問題均在二維中 1.單點修改,單點查詢 這個最簡單,直接開乙個二維陣列搞一搞就完事了。2.單點修改,區間查詢 ans sum x2,y2 sum x1 1,y2 sum x2,y1 1 sum x1 1,y1 1 inlin...
樹狀陣列 二維
首先初始陣列還是a陣列,二維的 搞乙個b陣列,也是二維,b i 就是a陣列第i行的一維樹狀陣列 b 2 1 a 2 1 b 2 2 a 2 1 a 2 2 b 2 3 a 2 3 最後我們來搞乙個c陣列,當然它還是二維的hhh c 1 就是第一行的樹狀陣列,c 2 是第一行加第二行,c 3 是第三行...
二維樹狀陣列
什麼是二維樹狀陣列 二維樹狀陣列 單點修改,區間查詢 include const int maxn 4096 5 typedef long long ll ll c maxn maxn int n,m int lowbit int x void modify int x,int y,int z ll...