# 進階資料結構與莫隊算法—區間問題概述
###### tags: `108 師大附中校隊培訓`
###### wiwiho
---
## 什麼是區間問題
----
區間指的是序列中一段連續的部分
----
有些題目會叫你修改某個區間
或問你某個區間的各種值
(例如最大、最小、數字和、公因數……)
也可能有修改、也有查詢
----
給一個長度為 $n$ 的數列
接下來有 $q$ 筆詢問
詢問有兩種類型:
1. 將 $[l, r]$ 這個區間的數字全部加上 $x$。
2. 輸出 $[l, r]$ 這個區間的最大值。
----
這是很經典的區間最大值問題
題目會要求你做兩種事
而且它是一下子要修改、一下子要查詢
----
暴力修改、暴力查詢?
修改和查詢時間都是 $O(n)$
乘上詢問筆數就會變成 $O(nq)$
----
有點慢?
這種問題非常多元
有很多手法和資料結構
來處理這種問題
---
## 區間問題的類型
----
## 操作(詢問)類型
### 修改
可能是改數字、把數字加上某個值、把數字開根號……等等
可能一題裡面有多種修改
也可能會很複雜
### 查詢
數字的和、最大的數字……
----
## 範圍類型
區間:可能不只一個數字
單點:只有一個數字
----
- 區間修改、區間查詢
- 區間修改、單點查詢
- 單點修改、區間查詢
- 區間修改,沒有查詢
- 區間查詢,沒有修改
----
不同範圍類型的問題
可以套不同的作法
----
根據題目不同
可以選擇不一樣的作法
---
## 前綴和
----
長度 $n$ 的數列 $A=\{A_1,A_2,...,A_n\}$
令 $S_i=\sum_{k=1}^i A_k$
$S$ 就是 $A$ 的前綴和序列
每一個 $S_i$ 都是 $A$ 的一個前綴和
----
給一個長度為 $n$ 的數列 $A=\{A_1,A_2,...,A_n\}$
有 $q$ 筆詢問
每筆詢問求區間 $[l,r]$ 所有數字的和
----
只有查詢區間和
不過如果暴力做
複雜度會變成 $O(nq)$
----
用前綴和去想
----
$$S_r-S_{l-1}=\sum_{k=0}^r A_k-\sum_{k=0}^{l-1}A_k
\\=\sum_{k=l}^r A_k$$
----
$O(n)$ 把所有前綴和算出來
每次查詢都只要 $O(1)$
→複雜度 $O(n+q)$
---
## 差分序列
給一個長度 $n$ 的數列 $A=\{A_1,A_2,...,A_n\}$
有 $q_1$ 次修改
每次修改將 $[l,r]$ 範圍中所有數字都加上 $x$
接著有 $q_2$ 次查詢
請輸出最後 $A_k$ 為多少
$1 \leq n,q_1,q_2 \leq 10^5$
----
做完全部修改,再做查詢
----
如果在區間修改的時候硬做
複雜度會變成 $O(nq_1)$
----
令 $S_i=A_i-A_{i-1}$、$A_0=0$
也就是 $S_i$ 是 $A_i$ 與它前一項的差
$[l,r]$ 都加上 $x$
那麼 $A_l - A_{l-1}$ 應該會多 $x$
而 $A_{r+1}-A_r$ 會少 $x$
----
區間修改變成單點修改了
----
怎麼推回 $A$?
$$\sum_{i=1}^k S_i=(A_1-A_0)+(A_2-A_1)+...+(A_k-A_{k-1})
\\=A_k$$
----
算出前綴和就可以得到 $A_k$ 了
這麼做一遍的話是 $O(n)$
如果是全部修改完再做查詢
就只要 $O(n)$ 算一次 $A$
再 $O(1)$ 查詢
----
一下修改、一下查詢?
每次修改完都要再重新花 $O(n)$ 算一次 $A$
太久
---
## 離散化
----
計算數字出現了幾次
$$1,1,2,3,5,3,3,4,4,2,2,2,1$$
$1$ 出現了 $3$ 次、$2$ 出現 $4$ 次……
----
如果開一個 map
來存每個數字出現了幾次?
不方便做區間問題
(例如大小介於 $[l,r]$ 的數字出現了幾次)
----
用 vector、陣列?
可能出現很大數字,導致記憶體開不下
----
用離散化
把數列中第一小的數字換成 $1$
第二小換成 $2$……
{"metaMigratedAt":"2023-06-15T01:14:27.578Z","metaMigratedFrom":"Content","title":"進階資料結構與莫隊算法—區間問題概述","breaks":false,"contributors":"[{\"id\":\"02353542-5acb-4a66-abd0-128b1af24abb\",\"add\":1984,\"del\":19}]"}