不難想到,用乙個陣列來模擬
就比如,單點修改就是這(時間複雜度為o(1));
a[x]
+= k;
求區間內的和
for
(int i = l -
1; i <= r; i++
) sum +
= a[i]
;
這樣的時間複雜度為o(n),如果查詢次數足夠多,就會超時
解決方法一:字首和
這樣在輸入時預處理,查詢只要o(1)時間。但是仔細想想,這樣的話,修改就需要o(n)的時間複雜度了。所以行不通。
解決方法二:樹狀陣列
什麼是樹狀陣列
這樣修改查詢都只需要o(log(n))的時間,大大優化了時間複雜度
例題:題目tp門
題目描述
如題,已知乙個數列,你需要進行下面兩種操作:
1.將某乙個數加上x
2.求出某區間每乙個數的和
輸入格式:
第一行包含兩個整數n、m,分別表示該數列數字的個數和操作的總個數。
第二行包含n個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。
接下來m行每行包含3個整數,表示乙個操作,具體如下:
操作1: 格式:1 x k 含義:將第x個數加上k
操作2: 格式:2 x y 含義:輸出區間[x,y]內每個數的和
樣例樣例輸入
321
2312
0213
樣例輸出
6
正解
這道題很簡單,就直接上**
#include
#define ll long long
const
int maxn =
1e6+5;
ll a[maxn]
, pre[maxn]
, bit[maxn]
;ll n, q;
ll lowbit
(ll x)
void
update
(ll x, ll k)
ll sum
(ll l, ll r)
void
read()
}void
write()
}int
main()
(注:這道題資料範圍比較大,要開long long)
例題:題目tp門
題目描述
給出乙個n*m的零矩陣a,你需要完成如下操作:
x y k:表示元素a[x][y]自增k ;
a b c d:表示詢問左下角為 ,右上角為 的子矩陣內所有數的和。
輸入格式
輸入的第一行有兩個正整數n, m ;
接下來若干行,每行乙個操作,直到檔案結束。
輸出格式
對於每個 2 操作,輸出乙個整數,表示對於這個操作的回答。
分析在一維後面多開乙個陣列就行了
pr[l]
[r]- pr[i -1]
[r]- pr[l]
[j -1]
+ pr[i -1]
[j -1]
;
這就是二維字首和
結合上面的式子,正解就出來了
#include
#define ll long long
const
int maxn =
4200
;ll bit[maxn]
[maxn]
;ll n, m, p;
void
read()
ll lowbit
(ll x)
void
update
(ll x, ll y, ll k)
ll sum
(ll x, ll y, ll l, ll r)
void
write()
}}intmain()
二維樹狀陣列 單點修改,區間查詢(模板)
給你乙個n m的鄰接矩陣,完成以下兩個操作。1 x y k 表示元素 ax,y 自增 k 2 a b c d 表示詢問左上角為 a,b 右下角為 c,d 的子矩陣內所有數的和。input 輸入的第一行有兩個正整數 n,m 接下來若干行,每行乙個操作,直到檔案結束。output 對於每個 2 操作,輸...
樹狀陣列 單點修改區間查詢
樹狀陣列,時間複雜度o mlogn 明顯優於暴力列舉以及字首和,主要用於單點修改區間查詢 當然還有區間修改單點查詢 如果一道題中只有區間查詢,那麼建議使用字首和維護 思想直接理解不好理解,借助資料 a陣列下標12 3456 78數值2 5632 714以上是我們要儲存的a陣列,就是原資料 b陣列下標...
樹狀陣列(單點修改區間查詢)
lowbit是用來取出二進位制中最低位數的1所代表的二進位制的值。只需要記下 就行了 int lowbit int x 將乙個樹的最子節點修改,則其父節點也需要更改,父父節點也需要修改。x x lowbit x 就是用來取出其父節點的。void add int x,int k 能查詢原陣列的字首和,...