1. 程式人生 > 其它 >輕重鏈剖分學習筆記

輕重鏈剖分學習筆記

這是第二遍 \(dfs\),定義:\(son[now]\)\(now\) 點的重兒子,\(topf\) 為當前的重鏈上深度最小的一個點也就是開始的點。我們在遍歷整棵樹的時候,會選擇先去遍歷這個點的左兒子然後再去管其他的點。我們在這一遍遍歷其實就是在給他們分配線段樹上的基本資訊以及記錄輕重鏈的基本資訊,在我們的輕重鏈剖分的時候,是會將重鏈看作是線段樹上維護的的一段連續區間,先訪問重兒子可以使得其的重兒子線上段樹上的維護的下標為它加一,也就是說是連續的,也就是一條重鏈對應連續的一段。


這是尋找 \(x,y\) 樹上路徑的相關資訊,定義:\(top[x]\)\(x\) 節點所在的重鏈的深度最小的節點(這裡節點均為樹上的編號),也就是這條重鏈的開始,\(dep[x]\)

\(x\) 節點在樹上的深度,\(id[x]\) 為節點 \(x\) 線上段樹上的編號。也就是這幾行程式碼是在查詢樹上 \(x,y\) 節點之間的路徑上經過的節點的權值和。我們一點點地去看。

首先看迴圈內部,第一個判斷條件就是尋找一個重鏈的起點深度最大的一個,也就是樹上最靠下的一個,然後查詢這條重鏈的資訊後就直接跳出這條重鏈,我們考慮跳深度大的一條鏈一定不會跳過頭,而跳深度小的一條鏈可能會跳過頭了,如下圖所示:

我們以紅色邊代表重邊,以黑色邊代表輕邊,我們看在這樣的情況下如果直接去跳過 \(y\) 所在的這條重鏈,那麼就會跳到節點 \(1\) 很明顯這不正確,所以就會選擇跳 \(x\)

所在的這條重鏈,這樣不可能會跳出去我們的正確路徑。

再看下邊的線段樹的詢問,因為我們的分配線段樹上的基本資訊是自根到底,所以深度小的節點線上段樹上的編號就小,深度大的節點線上段樹上的深度就大,所以查詢的區間左端點是這條重鏈的開始,右端點是它本身。

再看下邊關於跳過這條重鏈的情況,我們的 \(x\) 跳要跳到其重鏈的開始的父親節點,因為如果我們不是跳到父親結點的話,我們一是會將其重鏈開始的節點的資訊重複計算,二是我們可能下一次跳還是選擇這一條重鏈,但是它的起點就是當前的 \(x\) 節點,所以就死迴圈了。

翻過來看一眼迴圈條件,這個迴圈條件相當於是在約束 \(x,y\) 不在同一條重鏈上,因為我們迴圈是在跳重鏈,所以如果它們在同一條重鏈上那麼這條重鏈肯定不能直接跳過了,就應該直接在這條重鏈上去詢問 \(x,y\)

的線段樹上的相關資訊,因為他們在同一重鏈,所以編號一定是連續的,直接詢問那一段就可以了。

最後三行,因為深度大的節點線段樹上的編號也大,所以線段樹上的區間就是從深度小的節點到深度大的節點。

注意:

我們所給他們分配的線段樹上維護的下標或者叫編號就相當於 \(dfs\) 序,所以滿足 \(dfs\) 具有的性質