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
2/17
線段樹是用來處理區間問題的一種資料結構
這堂課先講單點加值和區間查詢
區間加值下堂課會講
結構
線段樹的結構大概會長這樣:
- 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\)個數字
我們會用開以\(4n\)為長度的陣列
樹高為\(logn\)
- 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\)
- 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 →當前節點\(i\)有區間\([l,r]\)
定義\(mid=(l+r)/2\)
左節點的區間為\([l,mid]\)
右節點的區間為\([mid+1,r]\)
以下我們用這題來講解線段樹
給一個長度為\(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]\)內的最大值
- 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 →第\(5\)個節點表示區間\([3,4]\)的最大值為\(11\)
第\(3\)個節點表示區間\([5,8]\)的最大值為\(43\)
建樹
可以發現葉節點的區間長度皆為1,以區間長度等於1為結束遞迴的條件
pull()為更新答案的函式
對於不同的答案他會長的些微不一樣
以區間求最大值而言:
區間查詢
給你一個區間\([sl,sr]\),你要如何快速找到這區間內的最大值
可以分成三種case去做:
- 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 →上圖\([l,r]\)在\([sl,sr]\)裏面,直接回傳\(75\)
- 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 →上面兩種case的左區間都有跟\([sl,sr]\)交集到,要往左遞迴
- 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 →上面兩種case的右區間都有跟\([sl,sr]\)交集到,要往右遞迴
注意第2和第3的case是獨立的,以下情況2,3都會成立,左右兩邊都要遞迴:
- 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 →查詢\([2,7]\)這個區間的最大值
- 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 →[0,8]左右兩個子區間都有跟[2,7]交集到
先往左遞迴
- 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 →[0,4]左右兩個子區間都有跟[2,7]交集到
先往左遞迴
- 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 →[0,2]只有右邊子區間有跟[2,7]交集到
往右遞迴
- 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 →找到[2,2],[2,2]這個區間在[2,7]內,回傳這個區間的最大值
- 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 →回到[0,4],因為右區間[3,4]有跟[2,7]交集到,往右遞迴
找到[3,4]這個區間在[2,7]內,回傳這個區間的最大值
- 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 →回到[0,8],因為右區間[5,8]有跟[2,7]交集到,往右遞迴
- 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 →[5,8]左右兩個子區間都有跟[2,7]交集到,先往左遞迴
然後找到[5,6]在[2,7]這個區間內,回傳這個區間的最大值
- 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 →回到[5,8],因為右區間[7,8]有跟[2,7]交集到,往右遞迴
- 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 →[7,8],因為左區間[7,7]有跟[2,7]交集到,往左遞迴
因為[7,7]在[2,7]內,回傳這個區間的答案
- 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 →總共有[2,2],[3,4],[5,6],[7,7]這些區間
- 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 →實作查詢:
複雜度:\(O(logn)\)
單點修改
以剛剛那顆線段樹舉例
我們要修改區間[1,1]的值把5變成17
- 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 →首先先從跟節點遞迴找到[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 →由下往上更新經過的點的最大值
- 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 →由下往上更新經過的點的最大值
- 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 →更新完畢
- 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 →實作單點更新
複雜度\(O(logn)\)
線段樹完整程式碼:
區間求總和
給一個長度為\(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 →不難發現對於一個大區間而言,大區間的總和為左右兩個小區間相加
- 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 →像是區間[3,4]的值等於[3,3]+[4,4]
區間[5,8]的值等於[5,6]+[7,8]
build函式會跟區間求最大值一模一樣,因為只有更新答案的pull函式會不一樣,以下是區間求總和的pull函式
先來講這題的區間查詢🐍
這裡查詢[4,7]的總和
- 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 →先看[0,8]的左右兩個子區間有沒有跟[4,7]交集到
因為都有,所以先往左遞迴
- 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 →現在到了[0,4],只有右邊有跟[4,7]交集到,往右邊遞迴
- 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 →目前為[3,4],只有右邊有跟[4,7]交集到,往右邊遞迴
- 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 →目前為[4,4],因為這個區間被包含在[4,7]裡面,回傳這個區間的答案
- 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 →回到[0,8],解決右邊的部分還沒解決的部分,所以現在在[5,8]
因為[5,8]的左右兩個子區間都有跟[4,7]交集到,先往左遞迴
- 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 →因為[5,6]的被[4,7]包含,回傳這個區間的答案
- 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 →回到[5,8]解決右邊還沒解決的部分,所以現在到[7,8]
因為[7,8]的左區間跟[4,7]交集,右邊沒有,所以往左遞迴
- 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 →現在到[7,7],因為[7,7]在[4,7]內,所以回傳這個區間的答案
- 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 →總共有[4,4]、[5,6]、[7,7]這些區間
- 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 →區間查詢code be like:
單點加值的話
這裡假設要在第三個單點加值7,也就是[2,2]這個區間
一樣先透過遞迴找到[2,2]這個區間
- 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 →因為是加上7,所以[2,2]這個區間變成16
- 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 →所經過的節點也要由下往上更新
- 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\)的陣列\(a\),有\(q\)個操作,分為以下2種:
觀察到每次詢問的正和負都是交替的
而\(l\)的位置固定為正
因此可以用\(l\)所在位置的奇偶性來建樹
根據不同的\(l\)再去判斷要用哪顆線段樹去query就好了
例題:區間不同數字數量
給一個長度為\(n\)的陣列\(a\),\(q\)筆操作,有以下兩種操作
\(1 \le n,q \le 10^5\)
\(1 \le a_i \le 40\)
\(a_i\)最多有四十種,對於每一種\(a_i\)開一棵線段樹
時間複雜度:\(O(nlogn)\)
空間複雜度:40*4*100000*4bytes
或是可以開一顆線段樹,裡面存long long的數字
long long可以存 64個bit,每一種bit存不同數字
再用or去運算求答案
例題:區間最大連續和
給一個長度為\(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 →ans是指每個區間的答案
如果大區間的最大連續和橫跨兩個區間並且為答案
- 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 →把每個節點的資訊包成struct
總和:
- 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 →\(seg[id].sum=seg[cl(id)].sum+seg[cr(id)].sum\)
最大前綴:
- 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 →\[ seg[id].pre=max \begin{cases} seg[cl(id)].pre \\ seg[cl(id)].sum+seg[cr(id)].pre \end{cases} \]
最大後綴:
- 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 →\[ seg[id].suf=max \begin{cases} seg[cr(id)].suf \\ seg[cr(id)].sum+seg[cl(id)].suf \end{cases} \]
區間連續最大和:
- 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 →\[ seg[id].ans=max \begin{cases} seg[cl(id)].ans \\ seg[cr(id)].ans \\ seg[cl(id)].suf+seg[cr(id)].pre \end{cases} \]
因此會這樣更新:
線段樹上二分搜
由於線段樹上每個大區間都會二分成兩個小區間
因此可以做一些二分搜之類的操作
例題:第k個1
長度為\(n\)的陣列\(a\)內只有0和1兩種數字,\(q\)筆操作
分為以下兩種:
\(1 \le n,q \le 10^5\)
假設陣列為a=[0,1,1,1,0,1,1,0]
可以以建區間總和的線段樹來做
這裡假設要查第四個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 →左區間有三個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 →左區間有一個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 →左區間有零個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 →找到了,回傳這個區間的\(l\)或\(r\)
- 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\)
跟上一題概念一樣只是換成區間求最大的線段樹
能往左區間走就往左,否則往右
直到走到最下面,並回傳這個位置的\(l\)或\(r\)
- 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=8\)的例子
來實作吧:
homework link