1.dfs;
2.線段樹。
相信dfs大家都會,估計只有線段樹了。
如果有不會的請點這裡:線段樹系列文章(未完)
就是將一棵樹分成許多條鏈,使得樹中所有節點都被包含在這些鏈裡。
(換句話說:就是一種使你的**瞬間增加1kb的演算法。)
#怎麼剖分?
1.隨便剖分
隨便找乙個節點,將它作為鏈頭向下剖分。
2.隨機剖分
隨便剖分+一點特判。
3.輕重鏈剖分
將重邊(後面會講)連成鏈。
顯然,對於隨機資料,三種方法沒什麼區別。
但是對於第
一、二種方法,若使用刻意構造的資料去測試,則會被卡掉。
綜上所述,為了保險起見,也為了演算法穩定性,我們選擇輕重鏈剖分。
重兒子:對於每個節點的兒子,若該兒子所在的子樹的大小是所有兒子中最大的,則稱該兒子為重兒子。每個節點有且只有乙個重兒子。
輕兒子:除了重兒子的節點。
重邊:連線重兒子與其父親節點的邊。
輕邊:連線輕兒子與其父親節點的邊。
重鏈:由重邊連線而成的鏈。注意鏈內有且只有重邊。
相信你也看不懂(hhh),舉個例子吧:
如圖,在這棵樹中:紅框框著的點就是重兒子,紫色邊表示重邊,黑色邊表示輕邊。可以看出兩條重鏈:和。而且,我們發現,重鏈的起點都是輕兒子。
然後,我們可以對所有節點進行重編號(優先重兒子),就會得到如下的結果:(藍色點即為新標號)
我們發現:重鏈中,標號都是連續的。於是,我們可以想象一下:將所有重鏈按鏈首標號進行排序,並拉直平放起來;我們就得到了乙個線性的序列。
並且:我們可以發現一些性質:
性質一:對於兩個節點u,v,若v是u的輕兒子,則有:siz[v]<=siz[u]/2,若v是u的重兒子,則:siz[v]>siz[u]/2;
性質二:對於乙個任意節點u,它到根節點的路徑最多有log2
n\log_2 n
log2n
條輕邊,log2
n\log_2n
log2n
條重路徑。
接下來就很玄學了
由上一步可知,我們得到了乙個序列,於是,我們就可以把這一堆東西扔給線段樹了。
我們可以進行權值修改、路徑查詢等操作,而做到這一切,都只需要o(n
log2n
)o(n\log_2n)
o(nlog2
n)的時間複雜度。
先扔來一堆陣列名字:
val[1...n]
:記錄每個節點的權值(讀入時);
siz[1...n]
:記錄以該節點為根的子樹的大小;
top[1...n]
:記錄每個節點所在重鏈的鏈首;
son[1...n]
:記錄每個節點的重兒子;
dep[1...n]
:記錄該節點在樹中的深度;
tid[1...n]
:記錄每個節點的新標號;
rnk[1...n]
:記錄新標號所對應的節點,是tid
的反函式;
fa[1...n]
:記錄每個節點的父親節點。
暈了對吧?別慌,其實都非常有用的,理解了就非常容易。
這次dfs我們主要處理一些基礎資訊,即:siz
、son
、dep
和fa
四個陣列。
這種事情應該不會很困難吧?直接粘**了。
void
dfs1
(int u,
int f,
int d)
}
struct tnode e[
2*maxn+5]
;tnode *g[maxn+5]
,*ecnt=
&e[0];
void
addedge
(int u,
int v,
int w)
這次dfs主要處理剩下的資訊:top
、tid
和rnk
三個陣列。
我們在dfs傳入乙個引數tp
,表示當前所在重鏈的鏈首,若遇到輕兒子則將tp
設為該節點並繼續往下傳。
在處理tid
,rnk
時,我們開乙個全域性變數dcnt
,每次進dfs時加一,就可以處理出這些資訊了。**如下:
void
dfs2
(int u,
int tp)
}
做完這些後,我們就完成了整個樹鏈剖分的實現。
剩下的就是各種資料結構的事情了。
例題1:spoj qtree query on a tree
樹鏈剖分詳解
樹鏈剖分定義 只是把一棵樹拆成鏈來處理而已,即將樹上的某些段一起通過資料結構優化進行處理來降低複雜度。樹鏈剖分相關定義 重兒子 ve v 為 u 的子節點中ve 值最大的,那麼 v 就是 u的重兒子 將子樹中最長的那一條鏈一起處理來降低複雜度 輕兒子 u 除了重兒子的其它子節點。重邊 點 u與其重兒...
詳解樹鏈剖分
樹鏈剖分,顧名思義為將鏈剖開分成多條。當我們想要修改樹上一條路的值或求值時,我們暴力只能用乙個個修改,這是非常慢的。這時,我們就要想乙個辦法,資料結構?但是資料結構我們都需要連續修改,可是樹上路徑的編號是不連續的。於是我們想了乙個辦法。我們先定義 fa x 為x的父親 dep x 為x的深度 siz...
樹鏈剖分詳解
重兒子 對於每乙個非葉子節點,它的兒子中 以那個兒子為根的子樹節點數最大的兒子 為該節點的重兒子 ps 感謝 shzr大佬指出我此句話的表達不嚴謹qwq,已修改 輕兒子 對於每乙個非葉子節點,它的兒子中 非重兒子 的剩下所有兒子即為輕兒子 葉子節點沒有重兒子也沒有輕兒子 因為它沒有兒子。重邊 乙個父...