or
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up
Syntax | Example | Reference | |
---|---|---|---|
# Header | Header | 基本排版 | |
- Unordered List |
|
||
1. Ordered List |
|
||
- [ ] Todo List |
|
||
> Blockquote | Blockquote |
||
**Bold font** | Bold font | ||
*Italics font* | Italics font | ||
~~Strikethrough~~ | |||
19^th^ | 19th | ||
H~2~O | H2O | ||
++Inserted text++ | Inserted text | ||
==Marked text== | Marked text | ||
[link text](https:// "title") | Link | ||
 | Image | ||
`Code` | Code |
在筆記中貼入程式碼 | |
```javascript var i = 0; ``` |
|
||
:smile: | ![]() |
Emoji list | |
{%youtube youtube_id %} | Externals | ||
$L^aT_eX$ | LaTeX | ||
:::info This is a alert area. ::: |
This is a alert area. |
On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?
Please give us some advice and help us improve HackMD.
Syncing
xxxxxxxxxx
線段樹 1
Introduction to Competitive Programming
3/20
結構
- The image was uploaded to a note which you don't have access to
- The note which the image was originally uploaded to has been deleted
Learn More →- The image was uploaded to a note which you don't have access to
- The note which the image was originally uploaded to has been deleted
Learn More →我們會用陣列表示一顆線段樹
假設總共有 \(n\) 個數字
樹高為 \(\lceil \log n \rceil + 1\)
節點數為 \(2^{\lceil \log n \rceil + 1} - 1\)
我們可以把陣列大小開 \(4 * n\)
( \(2^{\lceil \log n \rceil + 1} - 1 < 4 \times 2^{\log n}\) )
- The image was uploaded to a note which you don't have access to
- The note which the image was originally uploaded to has been deleted
Learn More →當前節點的index為\(i\)
左子節點為\(2i\)
右子節點為\(2i+1\)
如果一段區間的資訊可以透過兩個子區間的資訊來合併
就可以使用線段樹
每個節點存取一段區間的資訊
透過合併不同節點的資訊可以獲得任何一段區間的答案
簡單例題
給一個長度為\(n\)的陣列\(a\),有\(q\)個操作,分為以下2種:
\(1 \le n,q \le 2*10^5\)
- The image was uploaded to a note which you don't have access to
- The note which the image was originally uploaded to has been deleted
Learn More →假設當前陣列是a = [ 1, 5, 16, 7, 11, 4, 43, 15, 3]
當前節點\(i\)有區間\([l,r]\)
代表的是區間\([l,r]\)內的最大值
建樹
可以發現葉節點的區間長度皆為1,以區間長度等於1為結束遞迴的條件
有 左閉右開 / 左閉右閉 許多版本 這裡的code是左閉右開
區間查詢
假設要查詢區間 [2, 6]

就是拿這三塊去merge
可以簡單分成 3 種情況
不相交的話當前區間資訊沒有意義
包含的話不用繼續遞歸他的子節點
其他情況要繼續遞歸
單點修改
如果要修改 [7] 綠色的部分都有可能被修改

我們先遞歸找到最底下長度為 1 那個要修改的點
修改那個點,然後往上合併更新他的父節點
區間求總和
給一個長度為\(n\)的陣列\(a\),有\(q\)個操作,分為以下2種:
\(1 \le n,q \le 2*10^5\)
可以發現就只是區間求最大值換成區間求總和

可以建出區間求總和的線段樹
arr = [1, 5, 16, 7, 11, 4, 43, 15, 3]
如果要查區間 [2, 6] 總和

就會是這三個區間加在一起
會發現不一樣的地方只有合併兩個小區間的部分
區間查詢
單點修改
因為線段樹要維護的資料不一定只有一個數字
所以實作的時候可以用struct來存你需要的資料
細節可以看完整程式碼
完整程式碼
左閉右開
休息一下,等等有一堆例題講解!
例題:正負交替
給一個長度為\(n\)的陣列\(a\),有\(q\)個操作,分為以下2種:
可以發現要查詢的左界都是正的
可以用兩個線段樹
根據不同的\(l\)再去判斷要用哪顆線段樹去查詢就好了
例題:區間不同數字數量
給一個長度為\(n\)的陣列\(a\),\(q\)筆操作,有以下兩種操作
\(1 \le n,q \le 10^5\)
\(1 \le a_i \le 40\)
因為數值不大
每一個節點開一個bitset
合並的時候用or就好
例題:區間最大連續和
給一個長度為\(n\)的陣列\(a\),有\(q\)個操作,分為以下2種:
\(1 \le n,q \le 2*10^5\)
前面說過只要兩個區間的資訊可以合並成大區間的資訊就可以使用線段樹
怎麼維護最大連續和?
可以發現要維護最大連續和需要最大前綴和最大後綴
維護最大連續和又需要區間總和
L.sufix就是左子樹的後綴最大 (以此類推
sum = L.sum + R.sum
prefix = max(L.sum + R.prefix, L.prefix)
sufix = max(R.sufix, R.sum + L.sufix)
ans = max(L.ans, R.ans, L.sufix + R.prefix)
線段樹上二分搜
由於線段樹上每個大區間都會二分成兩個小區間
因此可以做一些二分搜之類的操作
例題:第k個1
長度為\(n\)的陣列\(a\)內只有0和1兩種數字,\(q\)筆操作
分為以下兩種:
\(1 \le n,q \le 10^5\)
假設陣列為 arr = [1, 0, 1, 0, 1, 0, 0, 1, 1]
可以以建區間總和的線段樹來做
這裡假設要查第三個1在哪裡
- The image was uploaded to a note which you don't have access to
- The note which the image was originally uploaded to has been deleted
Learn More →藍色數字代表要查當前區間的第幾個
- The image was uploaded to a note which you don't have access to
- The note which the image was originally uploaded to has been deleted
Learn More →例題:至少大於K的第一個元素
給一個長度為\(n\)的陣列\(a\),\(q\)筆操作,有以下兩種操作
\(1 \le n,q \le 10^5\)
可以發現要維護區間最大,才能知道這個區間有沒有大於K的元素
其他跟上一題一樣
來練習._.
題目