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 以及若干通道組成 並且每條通道連線了恰好兩個洞穴。假如兩個洞穴可以通過一條或者多條通道按一定順序連線起來 那麼這兩個洞穴就是連通的,按順序連線在一起的這些通道則被稱...