lct幾個月前就學了,花了我一整天問alan_cty才搞會
lct的左右就是維護樹上的一些值,和樹鏈剖分有相同的作用,也有超過樹鏈剖分的作用
lct也就是動態樹,意思就是樹是會動的,也就是有連邊和刪邊兩個操作
和鏈剖一樣,邊可以分為兩種,重邊(偏愛邊)和輕邊。一條重邊連起來的是一條鏈,在同一棵splay中(也就是說有好多棵splay)
這樣就會有兩種樹,我稱之為原樹和splay
splay中左子樹都比當前點在原樹中淺,右子樹則都比當前點在原樹中深
定義:
fa[x]表示x在splay中的父親,沒有就是0
p[x]為x在原樹中的輕邊父親(path parent),若沒有或原樹中x與它父親的邊為重邊則為0
root為原樹的根
如在上左圖中,p[d]=b,而p[e]=0
access(x)表示將x到root之間的所有邊變成重邊,也就是把這些點放到同一棵splay中
注意一點,如上圖中access(n)之後,原來a和b是重邊,變成了輕邊,這是因為乙個點與所有兒子中只能有一條重邊
code
t[x][0/1]為splay中x的左/右子樹
void access(int x)
}
splay(x,y)就是在splay中將x旋轉到y的下面
結合**和再畫一下圖,應該可以理解
這個操作是lct的核心
這個理解了,就相當於理解了lct
注意:splay中的rotate操作在lct中略微有點不同,因為有p這個陣列,所以rotate在旋轉的時候也要考慮到p
code
bool lr(int x)
void rotate(int x)
void splay(int x,int y)
}
makeroot(x)表示把x變成原樹的root
**:
void makeroot(int x)
rev為翻轉標記
access(x)之後,x所在的splay中就有且只有x到root上的所有點,此時x在最深處
將splay旋轉之後x就變成了最淺的點,也就是root
當splay被破壞或者被修改時,這個翻轉會以p傳到原樹中,所以是正確的
這個是lct操作中很重要的乙個
接下來的操作就是用來玩的了
**
void link(int x,int y)
很好理解吧?將x和y連邊(保證原來沒邊,連之後不形成環)
把x變成原樹的根,將x的輕邊父親變成y
**
void cut(int x,int y)
這個高階一點
切掉x和y之間的連邊(保證原來有邊)
在makeroot和access後,splay就只有x和y兩個點,斷掉之間的邊,維護好fa和p即可
當要修改或查詢原樹中x到y路徑上的點時:
makeroot(x);access(y);splay(x,0);
這樣之後,splay中x就代表了x到y路徑
因為維護的資料都在點上,所以維護邊的值時,要多開乙個點,代表邊的值,並與原來邊相連的兩個點連邊,之後與上面點的修改查詢一樣
最簡單的:
洛谷和bzoj中有 [hnoi2010]bounce 彈飛綿羊
就只用link,cut,查詢樹的大小
我的詳細題解這裡
稍複雜的:
很多oj都有 【noi2014】魔法森林
我的詳細題解這裡
更難一點的:
【gdsoi2017】中學生資料結構題
我的詳細題解這裡
有大神找到錯誤的歡迎補充和打臉
Link Cut Tree學習小記
link cut tree簡稱lct,是維護動態樹方式的一種,是乙個可以對樹進行新增鏈或子樹,刪除鏈或子樹等等,可以支援對樹的結構進行修改的演算法。樹鏈剖分只能維護靜態樹,就是只能對樹上的點的值進行修改的演算法,一般還是用線段樹來維護的。所以lct就厲害了,首先是維護方式不同,其次它是用splay來...
Link Cut Tree學習總結
title link cut tree學習總結 categories 演算法 date 2016 1 14 21 30 00 tags lct,演算法 lct是一種用於解決動態樹問題的資料結構。大體上的感受,lct就是樹鏈剖分和splay的結合版,什麼意思呢?因為要動態維護樹的結構和樹上的資訊,所以...
Link Cut Tree 學習筆記
link cut tree,用來解決動態樹問題。巨集觀上,lct維護的是森林而非樹。因此存在多顆lct。有點像動態的樹剖 鏈的確定通過 access 操作 每條鏈用一顆 splay 維護。splay 維護鏈的關鍵字是深度,因此一條鏈的頂端就是 splay 中鍵值最小的點 由於lct的資料有很多,在此...