區間修改,查詢之樹狀陣列

2022-09-11 01:03:25 字數 4461 閱讀 6001

方法:

①單點修改,單點查詢

(這個沒什麼好說的,就是單純的陣列)

②單點修改,區間查詢

樹狀陣列:樹狀陣列能單點修改,並且區間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 4

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 }

acwing 242.乙個簡單的整數問題樹狀陣列處理區間相加,單點查詢

差分與樹狀陣列的結合,樹狀陣列本身可以求解單點修改,區間查詢的任務。和差分結合起來,將樹狀陣列中儲存的值改為差分的值,那麼就可以求解區間修改,單點查詢的任務。

1 #include 2 #include 3 #include 4

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 }

acwing 243.乙個簡單的整數問題2差分+字首和+樹狀陣列構造求解區間修改區間查詢

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 4

5using

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