Link Cut Tree 學習筆記

2022-05-31 04:06:12 字數 3160 閱讀 1051

link-cut tree,用來解決動態樹問題。

巨集觀上,lct維護的是森林而非樹。因此存在多顆lct。有點像動態的樹剖(鏈的確定通過$access$操作),每條鏈用一顆$splay$維護。$splay$維護鏈的關鍵字是深度,因此一條鏈的頂端就是$splay$中鍵值最小的點

由於lct的資料有很多,在此不詳細闡述。只是談談理解有困惑的幾個點,其中大多已經解決了:

關於虛邊

這裡的虛邊其實不能算叫邊,只能說是乙個父指標。由於splay是二叉樹,但有可能出現有好多虛邊指向乙個點的情況。因此虛邊其實就是兒子認爸爸,而爸爸不認兒子

虛邊的真正作用其實是連線每顆splay,換句話說,虛邊其實就是每顆splay根節點的父指標,指向另乙個splay中的節點。然而這個父指標並不會因為rotate而被破壞,因為這裡和普通的splay不同,在rotate的過程是有可能涉及到別的splay中的點(也就是gf),在rotate時,我們一定會把原本指向gf的節點f改為x

關於$access$操作

access操作用來讓乙個節點x到當前lct的根節點的整條路徑都變為實邊(並且節點x與下方的實邊斷開,成為最底部的點)。形象的說,由於每個點只能在乙個splay中,有的實邊要變為虛邊。access操作時lct動態維護森林的根本,而之所以能夠達到動態效果正是由於實鏈的不斷變換

因此我們可以從x開始向上走,每一次將當前節點(一定是當前splay中深度最大的)splay到根,由於它是深度最大的,一定沒有右兒子。因此可以把它的右兒子接上上一輪的splay(第一輪就接上空的)。注意這裡的接兒子只需要改變ch的值,而不用更新fa(因為原本是虛邊,兒子一定認爸爸)。如果它本身就有右兒子也不管,這樣接上另乙個兒子之後,原來的兒子依然認它為爸爸,然而爸爸卻突然之間不認它了,因此就變成了虛邊。

關於$makeroot$操作

意義就是讓節點x成為當前splay的根。因此可以先access(x),然後splay(x)(注意splay不會改變任何關係)。此時由於x已經被access了,因此一定是深度最大的節點。所以splay之後一定沒有右兒子。此時想讓x成為根,那麼也就是深度最小。開始發揮splay最重要的作用——翻轉。

說到關於懶標記的,splay中標記的下傳可以這樣操作(新學):對於要splay的節點x,先一路遞迴到達根節點,然後依次往下下傳標記。因為splay只會一路影響它的father,update也是乙個原理

問題:為什麼要整個翻轉,而不是只交換根的左右兒子呢?效果貌似一樣?雖然實測爆0,但還是不太懂為什麼……(我太弱了)

關於$findroot$操作

找根。最簡單的操作之一,先access和splay,此時最小的便是根

關於$split$操作

提取出x到y的鏈。只需要makeroot(x),然後access(y)。此時就打通了x到y的路徑(真的好動態哇)。為了方便查詢,splay(y),這樣從y一直找最小的就好了。也是灰常簡單滴

關於$link$操作

makeroot(x),然後把x的父親置為y

為什麼?為什麼?為什麼?

update:我可能腦子有點問題…… 其實把x的父親置為y相當於連了一條虛邊——此時他們合併為了乙個lct,其中x就在y的下面了,和正常的一樣

關於$cut$操作

依舊不難。要斷x到y的直接邊,那麼首先要把它提取出來,然後斷了就好了。如何提取?split啊!!!

但是注意如果要判斷這條邊是否存在有兩個條件,其一很簡單,$ch[y][0]==x?$。因為前面split的時候y被作為了splay的根節點,而因為它們是直接邊,所以高度差不超過1.因此就是左兒子

還有乙個條件是要滿足$ch[x][1]==0$,因為如果x存在右兒子,這個右兒子肯定比它大比y小,這樣差值就不是1了

口訣

旋轉記得判父親,伸展記得先下傳。

access記得要更新,link記得要mroot。

/*

by dennyqi 2018

*/#include

#include

#include

#include

using

namespace

std;

typedef

long

long

ll;const

int maxn = 300010

;const

int inf = 0x3f3f3f3f

;inline

int max(const

int a, const

int b)

inline

int min(const

int a, const

int b)

inline

intread()

intn,m,opt,x,y;

int val[maxn],ch[maxn][2

],fa[maxn],xr[maxn],tag[maxn];

struct

linkcuttree

inline

bool isroot(int

x) inline

void update(int

x) inline

void rotate(int

x)

void prepare(int

x) inline

void splay(int

x)

if(rson(gf,f) ^ rson(f,x)) rotate(x); else

rotate(f);

rotate(x);}}

inline

void access(int

x) }

inline

void mroot(int

x) inline

int findroot(int

x) inline

void split(int x, int

y) inline

void link(int x, int

y) inline

void cut(int x, int

y) inline

void change(int x, int

y)}qxz;

intmain()

return0;

}

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就厲害了,首先是維護方式不同,其次它是用splay來...

Link Cut Tree學習小記

lct幾個月前就學了,花了我一整天問alan cty才搞會 lct的左右就是維護樹上的一些值,和樹鏈剖分有相同的作用,也有超過樹鏈剖分的作用 lct也就是動態樹,意思就是樹是會動的,也就是有連邊和刪邊兩個操作 和鏈剖一樣,邊可以分為兩種,重邊 偏愛邊 和輕邊。一條重邊連起來的是一條鏈,在同一棵spl...