為了優化體驗(其實是強迫症),蒟蒻把總結拆成了兩篇,方便不同學習階段的Dalao們切換。
LCT總結——概念篇戳這里
題單
灰常感謝XZY巨佬提供的強力資磁!(可參考XZY巨佬的博客總結)
題單對於系統地學習一個知識點還是有好處的。
所以蒟蒻搜集了各處的LCT題目(其實作為近年新興的知識點,現有的好題不是很多,有些題樹剖也可做)
大概按細化分類進行整理(類比下面的幾個細化知識點,會有重復的列舉)
同一類中的題目也大概按難度遞增吧(太弱了,對每個題的難度定位或許有不准的地方,歡迎討論!)
維護鏈信息(LCT上的平衡樹操作)
- 【Done】洛谷P3690 【模板】Link Cut Tree
- 【Sol.】洛谷P3203 [HNOI2010]彈飛綿羊
- 【Sol.】洛谷P1501 [國家集訓隊]Tree II
- 【Todo】洛谷P2486 [SDOI2011]染色
- 【Sol.】洛谷P4332 [SHOI2014]三叉神經樹
動態維護連通性&雙聯通分量(可以說是並查集的升級,因為並查集只能連不能斷)
- 【Done】 洛谷P2147 [SDOI2008]Cave 洞穴勘測
- 【Sol.】 洛谷P3950 部落沖突
- 【Sol.】 洛谷P2542 [AHOI2005]航線規划
- 【Done】 BZOJ4998 星球聯盟
- 【Done】 BZOJ2959 長跑
維護邊權(常用於維護生成樹)
- 【Sol.】洛谷P4172 [WC2006]水管局長
- 【Todo】UOJ274溫暖會指引我們前行
- 【Sol.】洛谷P4180 [BJWC2010]次小生成樹
- 【Sol.】洛谷P4234 最小差值生成樹
- 【Sol.】洛谷P2387 [NOI2014]魔法森林
維護子樹信息
- 【Done】[COGS2701]動態樹
- 【Sol.】洛谷P4219 [BJOI2014]大融合
- 【Sol.】洛谷U19482 山村游歷(Wander)
- 【Sol.】洛谷U21715 首都(BZOJ3510權限題qwq)
- 【Todo】洛谷SP2939 QTREE5 - Query on a tree V
- 【Todo】LOJ558「Antileaf's Round」我們的 CPU 遭到攻擊
維護樹上染色聯通塊
- 【Todo】洛谷P2173 [ZJOI2012]網絡
- 【Sol.】洛谷P3703 [SDOI2017]樹點塗色
- 【Sol.】洛谷SP16549 QTREE6 - Query on a tree VI
- 【Sol.】洛谷SP16580 QTREE7 - Query on a tree VII
- 【Todo】BZOJ3914 Jabby's shadows
特殊題型
- 【Sol.】
洛谷P3613 睡覺困難綜合征洛谷P5354 [Ynoi2017]由乃的OJ - 【Todo】UOJ207 共價大爺游長沙
- 【Sol.】洛谷P3348 [ZJOI2016]大森林
- 【Sol.】洛谷P4338 [ZJOI2018]歷史
- 【Todo】LOJ2289 [THUWC 2017]在美妙的數學王國中暢游(數學對於我這種蒟蒻是不可做的TAT)
操作升級!(模板以外的細化總結)
維護鏈信息(LCT上的平衡樹操作)
思路與模板基本都很像了,就不展開討論了
例題1
洛谷P1501 [國家集訓隊]Tree II(點擊進入題目)
感覺難度評定也高了點吧
有了鏈上乘法和鏈上加法,那肯定是像線段樹區間修改那樣使用懶標記了。
放標記的做法來自[模板]線段樹2
那里發題解的Dalao們都講得挺好的,本蒟蒻參考一下。
蒟蒻的題解在這里
例題2
洛谷P3203 [HNOI2010]彈飛綿羊(點擊進入題目)
略帶一點思維,但是代碼比模板還簡單。。。。。。
在LCT模板基礎上進行靈活運用,可以使代碼和程序都做到高效。
蒟蒻的題解在這里
例題3
洛谷P4332 [SHOI2014]三叉神經樹
沒有那么裸了,仔細分析並利用好題目的性質
蒟蒻的題解在這里
動態維護連通性&雙聯通分量
維護連通性?findroot判一下就好啦!屬於模板范疇
至於雙連通分量,LCT好像只能資磁加邊。。。。。。
LCT中的每個點其實代表的是一個雙連通分量,維護每個點屬於哪個雙連通分量需要在外面弄一個並查集維護。
加邊時,如果兩點不連通就link;
如果連通就說明有環,把環縮成一個點,在並查集里也全部合並在一起
其中要注意很多細節,具體就看下下面例題2的代碼吧
例題1
洛谷P3950 部落沖突(點擊進入題目)
正解不是LCT。。。。。。
只是這里用LCT的思路非常簡單甚至於無腦。。。。。。
蒟蒻題解
例題2
洛谷P2542 [AHOI2005]航線規划(點擊進入題目)
基礎的動態維護雙連通分量,具體就看看題解吧
蒟蒻題解
維護鏈上的邊權信息(生成樹)
普通LCT維護點權,那對於邊權呢?比如要獲取一條路徑上最長的邊,等等。
這種維護的最經典的應用,大概就是動態維護一顆最小/大生成樹了(需要獲取邊長度等信息)。
我起初有一種想法。
一棵樹,除了根節點,每個節點有且僅有一條父邊。
那么如果我們只要邊的信息,可不可以就把LCT中的點的點權當成父邊的邊權呢?
在其它不少數據結構中好像是可以這樣做的。
只不過LCT性質非常特殊。一旦換了根,原先邊的父子關系就破壞了。所以並不能這樣做。
那又如何是好呢?
我在網上看到有些博客介紹的方法,是把邊置於LCT外,然后在LCT節點中維護父邊和重子邊的編號,需要更新信息時從外部獲取,在access,link,cut時額外更改。
這樣好像挺麻煩的,要維護那么多東西。
另一種更抽象的做法,也是我要分享的,就是兩個字——拆邊,把邊視作為一個點,向該邊的兩個端點連兩條邊。
只需要維護邊權的時候,邊權存在LCT中代表邊的點權里,因為不需要維護真正的點權,所以LCT中的代表點的點權可以設成空的(0),不會影響信息的正確性。於是就變成了維護點權。
當然了,原先我們的link和cut是對於兩個點的,現在有點不一樣了(因為兩點之間又多了一個代表邊的點)
update:發現之前描述的寫法有問題,且並不能優化多少常數,在這里更正一下
寫法就是link/cut兩次,比如
link(e[i].id,e[i].x);link(e[i].id,e[i].y);
cut(e[i].id,e[i].x);cut(e[i].id,e[i].y);
例題一
洛谷P4180 [BJWC2010]次小生成樹
其實這道題用LCT不是正解,不過是可做的(update:我后來又寫了LCT),放在這里一下吧。
用LCT維護最小生成樹,再去枚舉非樹邊嘗試替換樹邊,更新最優答案。
TPLY巨佬也用LCT做的(某問題導致常數巨大?),他的題解在這里
蒟蒻題解在這里
例題二
洛谷P2387 [NOI2014]魔法森林
我太弱啦!這種雙關鍵字的維護我是真的沒有思路,邊看着題解邊打出來的。orz XZY&XZZ兩位巨佬,題解點贊!
不過作為LCT維護邊權的好題目還是值得分享。
蒟蒻題解在這里
維護虛子樹信息總和與原樹信息總和
有時候,我們需要的並不是維護鏈的信息,而是子樹的信息。要知道,LCT是長於維護鏈的信息,而弱於維護子樹信息(這方面不得不承認樹剖的用處了,還要趕緊學)。然而動態的連邊和斷邊,又不得不要求我們使用LCT來維護。
其實,我們還是不會束手無策的。
維護子樹信息總和的一些常見題型,無非就是詢問整棵(原樹中的)子樹的總大小、權值總和、最值之類的東西。
我們已經可以通過輔助樹Splay來獲知Splay中的實子樹(也就是原樹中的一條鏈)的信息總和。
既然原樹的邊只有實與虛,子樹也只有實與虛,那么如果要想維護好原樹的信息總和,我們是不是首先要知道虛子樹的信息總和?
注:以下設虛子樹信息總和用數組si表示,原樹信息總和用s表示。此處si[x]只包含x所有虛子樹(通過輕邊指向x)的信息總和,而s[x]實際上是在LCT中的所有兒子的信息總和(包括輔助樹Splay中相對的左右兒子的總和與被輕邊所指的絕對的虛子樹的總和)。
那么如果我們確定了si[x]的值,是不是就知道了s[x]的值了?實加虛嘛!
這就是pushup,代碼
inline void pushup(int x){
s[x]=s[c[x][0]]+s[c[x][1]]+si[x]+1;//大小總和,注意別漏了+1,自己也要算上
//或者
s[x]=s[c[x][0]]+s[c[x][1]]+si[x]+v[x];//權值總和,自己同樣也要算上
}
先不對這種方法是怎樣來的這個問題追本溯源,那我們就可以直接考慮si如何維護了。
還是直接假設我們已經提前維護好了si吧。
很顯然,si的變化取決於虛實邊的變化,所以現在我們只考慮LCT中的每個操作會對虛實邊產生怎樣的影響。
- splay(x):顯然這一操作只會改變節點在輔助樹Splay中的相對位置,並不會對樹中的虛子樹信息產生任何影響。過程中的pushup會正確地更新s。
- access(x):這個時候,我們發現,循環中每一次splay(x)后,我們更改了x的右子樹,也就是更改了虛實邊,那么會對信息產生影響。
這里的影響,無非就是得到了一個虛兒子,失去了一個虛兒子,總和沒有改變。
於是直接改就好啦,si加上原來右兒子的s,再減去新的右兒子的s。
與原模板略有不同的代碼
inline void access(int x){
for(int y=0;x;x=f[y=x]){
splay(x);
si[x]+=s[c[x][1]];
si[x]-=s[c[x][1]=y];
pushup(x);
//如果pushup只是更新原樹信息總和s的話,甚至這里可以不寫,畢竟加一個減一個,和沒變
}
}
- makeroot(x):並無影響。雖然樹的形態翻轉了,但是翻轉的只是實鏈。
- findroot(x):顯然無影響(跳左兒子又沒改變樹的形態)
- split(x,y):顯然無影響(除了調用三個函數外什么都沒干)
- link(x,y):這就有影響了。y多了一個輕邊指向兒子x,那么s[y],si[y]都加上s[x]。注意,多了一個子樹,那么y在LCT中的祖先的s也都要加上s[x]的值,卻沒有得到更新。我們在加上s[x]前,需要額外地把y轉到根(access(y)+splay(y)),y就沒有祖先了,再加,就不會影響信息的正確性了。
與原模板略有不同的代碼
//保證連邊合法
inline void link(int x,int y){
split(x,y);//這里不是提取x-y的路徑的意思,是makeroot+access+splay的偷懶寫法
si[f[x]=y]+=s[x];
pushup(y);
}
//不保證
inline bool link(int x,int y){
makeroot(x);
if(findroot(y)==x)return 0;//access+splay已完成
si[f[x]=y]+=s[x];
pushup(y);
return 1;
}
- cut(x,y):無影響,斷掉的是一條重邊,pushup(y)更新s[y]就好啦。
分析到此完畢。其實好像也就只改了一點點地方。。。。。。不過思路是很巧妙的,值得用心體會。
補充一句,如果要維護子樹里的最值,一個套路是在每個節點開一個平衡樹維護該節點所有虛子樹的最值,以便進行查詢和更改。
例題一
洛谷P4219 [BJOI2014]大融合(點擊進入題目)
當學會了LCT維護子樹信息和以后,這題就變得有些裸了。。。。。。
蒟蒻題解在這里
例題二
洛谷U19482 山村游歷(Wander)(點擊進入題目)
注:此題為WC模擬賽試題,版權歸出題人Philipsweng所有。小蒟蒻覺得這題出得很不錯,於是上傳至洛谷個人題庫,作為例題與大家分享。數據自測,如有問題歡迎反饋。
題目簡述:
沒有。。。。。。這是一個閱讀題,簡述的話就等於告訴你怎么做了
仔細讀一下題目吧,這道題水平挺高的。
思路分析:
也有點復雜
然而分析完了以后,又變成裸的了。。。。。。
算了,還是單獨建一篇隨筆吧。
蒟蒻題解在這里
維護樹上染色聯通塊
維護方法要視具體情況分析
可能可以開一個LCT然后把同色的點連起來,這樣做思路很簡單,但實現起來受局限
也可能有多少顏色就開多少個LCT,然后在對應顏色的LCT中連上
升級操作:修改點的顏色
需要轉化模型,可參考下面例題2
再次升級操作:修改鏈為同一種顏色
Link-Cut-Memphis(霧
看一下發明者Memphis巨佬的博客吧
以上兩種操作都是在ZJOI2018交流課上聽到的Orz
例題一
洛谷P3703 [SDOI2017]樹點塗色(點擊進入題目)
維護連通塊並不麻煩,只是思維難度超大。。。。。。
不會樹剖,焉知非福?
蒟蒻的題解
例題二
洛谷SP16549 QTREE6 - Query on a tree VI(點擊進入題目)
一直都把邊化為子節點,這次來把點化為父邊(霧
蒟蒻的題解
特殊題型
有一類題目是真的毒瘤,怪異到都幾乎認不出它的真面目
似乎並不能把它們歸為任何一類LCT題型或者任何一種套路
只好仔細分析題目,發現題目本身的特殊性,再轉化為LCT模型解決
然而我什么都分析不出來啊QwQ
例題一
洛谷P3613 睡覺困難綜合征洛谷P5354 [Ynoi2017]由乃的OJ
把起床困難綜合症——一個按位貪心的題目,完美地套在了LCT中
蒟蒻題解
例題二
洛谷P3348 [ZJOI2016]大森林
新技能get:虛點
離線的轉移思路也極為巧妙
蒟蒻題解
例題三
洛谷P4338 [ZJOI2018]歷史
ZJOI唯一可做題TAT
不來一些大力結論,根本做不下去。。。。。。
蒟蒻題解