SDOI2008 洞穴勘測 LCT模板

2022-05-09 20:05:47 字數 1735 閱讀 3721

bzoj 2049 傳送門

洛谷p2147 傳送門

這個大佬的lct詳解超級棒的!

link-cut tree的基本思路是用splay的森林維護一條條樹鏈。

splay的森林,顧名思義,就是若干splay組成的東西。

每個splay都有乙個根節點,所以lct裡的splay不能記錄根節點,因為根節點有好多。

我們開乙個bool陣列記錄每個點是否為根節點。

每個splay都維護一條重鏈,重鏈之間的輕鏈在splay裡只從兒子指向父親,而父親並沒有這個兒子。

就像圖里的紅箭頭。

每個splay都表示一條重鏈,這個splay的中序遍歷與鏈上節點的深度順序是一致的。

接下來是splay裡最重要的操作:access(p)

就是指打通從p到整棵樹的樹根的一條重鏈。

同時也把p下面接的鏈變成輕鏈。

之後還有乙個操作:move_to_root,把p變成整棵樹的根。

在access之後,p和樹根之間是重鏈直接連線,而乙個splay維護乙個重鏈,所以此時p和根已經在乙個splay裡了。

我們只需要splay(p)即可。

但是這樣的話破壞了深度的性質。

把左右反轉一下就行了:reverse(p)

接下來就是link和cut的操作。

link(x,y)很簡單,mtr(x),之後接一條從x到y的輕鏈即可。

cut(x,y)的話,mtr(x),access(y),splay(y),x就是y的左兒子了。刪掉父子關係即可。

查詢連通性:mtr(x),access(y),splay(y),x就在y的子樹裡了。x=f[x]一直往上跳,判斷最後y的終點是不是x。

這些大概是最最基礎的操作了,子樹資訊什麼的都不用維護。

1 #include2 #include3 #include4

#define id(x) (s[f[x]][1]==x)

5using

namespace

std;67

intn,m;

8int f[10005],s[10005][2];9

bool rev[10005],rt[10005

];10

11void reverse(int

p)12

1617

void pushdown(int

p)18

2425

void down(int

p)26

3031

void rotate(int

p)32

4344

void splay(int

p)45

55if(id(p)^id(fa))rotate(p);

56else

rotate(fa);

57rotate(p);58}

59}6061

void access(int

p)6271}

7273

void mtr(int

p)74

7980

void link(int x,int

y)81

8586

void cut(int x,int

y)87

9495

void check(int x,int

y)96

103104

intmain()

105118

return0;

119 }

SDOI2008 洞穴勘測 LCT

題目描述 輝輝熱衷於洞穴勘測。某天,他按照地圖來到了一片被標記為jszx的洞穴群地區。經過初步勘測,輝輝發現這片區域由n個洞穴 分別編號為1到n 以及若干通道組成,並且每條通道連線了恰好兩個洞穴。假如兩個洞穴可以通過一條或者多條通道按一定順序連線起來,那麼這兩個洞穴就是連通的,按順序連線在一起的這些...

SDOI2008 洞穴勘測

lct維護連通性型別的題目,主要是要搞清楚findroot函式的作用 判斷根是否相同,和並查集裡面的find 函式有異曲同工之妙,如果根相同可以認為兩個點具有連通性。先access打通一道到x的實邊,現在x是深度最大的節點。然後再splay x到根節點,因為它深度最大,這個時候它只有左子樹。所以找它...

SDOI2008 洞穴勘測

輝輝熱衷於洞穴勘測 某天,他按照地圖來到了一片被標記為jszx的洞穴群地區 經過初步勘測,輝輝發現這片區域由n個洞穴 分別編號為1到n 以及若干通道組成 並且每條通道連線了恰好兩個洞穴。假如兩個洞穴可以通過一條或者多條通道按一定順序連線起來 那麼這兩個洞穴就是連通的,按順序連線在一起的這些通道則被稱...