二維樹狀陣列學習筆記

2022-05-25 12:42:14 字數 3457 閱讀 2286

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...