方法:
①單點修改,單點查詢
(這個沒什麼好說的,就是單純的陣列)
②單點修改,區間查詢
樹狀陣列:樹狀陣列能單點修改,並且區間1 ~ n的和,區間查詢只需要用到字首和的思想就可以了。
線段樹:√
③區間修改,單點查詢
差分:區間修改只需改變兩個值,單點查詢時求一遍字首和。
樹狀陣列 + 差分:在進行修改的時候匯入的數是差分的值,最後樹狀陣列求和其實就是求一遍字首和答案過程。
線段樹:√
④區間修改,區間查詢
樹狀陣列:區間修改依舊是要將原陣列進行差分。區間查詢需要維護兩個字首和陣列。
原本的差分陣列為b陣列,b的字首和陣列是a陣列。
線段樹:√
複雜度:
差分:修改$o(1)$, 查詢$o(n)$。
樹狀陣列:修改$o(logn)$, 查詢$0(logn)$。
線段樹:修改$o(logn)$, 查詢$0(logn)$。
acwing 241.樓蘭圖騰
樹狀陣列處理大於小於數字的個數
該題的思路就是預處理每乙個點前面大於該點的數量,後面大於該點的數量,相乘即為v的個數。同理,對於倒v也是一樣,處理的是小於的值。
容易想到用樹狀陣列做,先從正面掃一遍,預處理兩個陣列up和down。然後再從後面掃一遍,用之前預處理的陣列與之相乘即為答案。時間複雜度$o(nlogn)$。
1 #include 2 #include 3 #include 4acwing 242.乙個簡單的整數問題樹狀陣列處理區間相加,單點查詢5using
namespace
std;
67 typedef long
long
ll;8
9const
int n = 200010;10
11int
tr[n], a[n];
12int
up[n], down[n];
13int
n;14
15int lowbit(int
x)16
1920
void add(int x, int
c)21
2425
int sum(int
x)26
3132
intmain()
4344 memset(tr, 0, sizeof
tr);
4546 ll res1 = 0, res2 = 0;47
for(int i = n ; i >= 1 ; i --)
4854
55 cout << res1 << "
"<< res2 <
56return0;
57 }
差分與樹狀陣列的結合,樹狀陣列本身可以求解單點修改,區間查詢的任務。和差分結合起來,將樹狀陣列中儲存的值改為差分的值,那麼就可以求解區間修改,單點查詢的任務。
1 #include 2 #include 3 #include 4acwing 243.乙個簡單的整數問題2差分+字首和+樹狀陣列構造求解區間修改區間查詢5using
namespace
std;67
const
int n = 1e5+10;8
9int
a[n], tr[n];
10int
n, m;
1112
int lowbit(int
x)13
1617
void add(int x, int
c)18
2122
int sum(int
x)23
2829
intmain()
46else
4753}54
55return0;
56 }
b為a的差分陣列,同樣,對於單點查詢查詢點x來說為$\sum_^b_i$,所以對於區間$1-x$的查詢為$\sum_^\sum_^b_i$。
顯然這是不能直接求解的。將其的各項羅列出來:
$b_1$
$b_1 + b_2$
$b_1 + b_2 + b_3$
$\cdot \cdot\cdot \cdot\cdot \cdot$
$b_1 + b_2+b_3 + b_4 +\cdot \cdot\cdot \cdot b_x$
然後將其對稱:
$ }$
$b_1+ }$
$b_1 + b_2+}$
$b_1 + b_2 + b_3+}$
$\cdot \cdot\cdot \cdot\cdot \cdot$
$b_1 + b_2+b_3 + b_4 +\cdot \cdot\cdot \cdot b_x$
所以黑色的部分為我們要求的和,那麼整個方形相加的和為$x*sum_1(x)$, 所求的面積的和是$x * sum_1(x) - (b_1 + 2b_2 + 3b_3 +\cdot \cdot\cdot \cdot + xb_x)$。
因此我們再處理乙個差分陣列是$ib_i$的樹狀陣列,區間查詢$1-x$的結果就為$x * sum_1(x) - sum_2(x)$。
樹狀陣列**:
1 #include 2 #include 3 #include 4線段樹**:5using
namespace
std;
67 typedef long
long
ll;8
9const
int n = 1e5+10;10
11int
a[n];
12ll tr1[n], tr2[n];
13int
n, m;
1415
int lowbit(int
x)16
1920
void add(ll tr, int
x, ll c)
2124
25 ll sum(ll tr, int
x)26
3132 ll get_sum(int
x)33
3637
intmain()
3849
50while(m --)
5161
else
6270}71
72return0;
73 }
1 #include 2 #include 3 #include 45using
namespace
std;
67 typedef long
long
ll;8
9const
int n = 100010;10
11int
n, m;
12int
w[n];
13struct
nodetr[4 *n];
1718
void pushup(int
u)19
2223
void pushdown(int
u)2432}
3334
void build(int u, int l, int
r)35;37
else38;
40int mid = l + r >> 1
;41 build(u << 1, l, mid), build(u << 1 | 1, mid + 1
, r);
42pushup(u);43}
44}4546
void modify(int u, int l, int r, int
d)47
53else
5461}62
63 ll query(int u, int l, int
r)64
7475
76int
main()
93else printf("
%lld\n
", query(1
, l, r));94}
9596
return0;
97 }
樹狀陣列之區間修改,單點查詢
首先我們開三個陣列 我們就形成了下面的這種資料結構 我們發現對於樹狀陣列 c i c i 來說,query i a i query i a i 也就是對應數的值.如果我們想 2 4 的數加 10 怎麼辦?我們只要修改 b i 陣列如下 我們就形成了下面的資料 我們不難發現差分陣列的字首和就是對應原陣...
樹狀陣列 區間修改,區間查詢
也許更好的閱讀體驗 好東西,以後可以不打線段樹了 本篇假定讀者都會最基礎的兩種樹狀陣列,即區改單查和單改區查 思考如何維護乙個區間的值,想到了差分 對乙個差分陣列做一次字首和可以得到每個位置的值 再對每個位置累加一下就是乙個區間的值 公式化的講,就是 設差分陣列為 c 則每個位置的值 val i s...
樹狀陣列區間修改區間查詢
題面 首先,我們要推乙個柿子。displaystyle sum a i 把a i 用差分陣列表示出來,就可以寫成 displaystyle sum sum d i 我們考慮一下,每個d i 出現的次數是一定的。那我們可以換一下列舉順序,先列舉d i 在列舉他出現的次數,就可以變成 displayst...