LCT入門筆記

2021-08-20 01:28:45 字數 3045 閱讀 9387

lct是動態樹的一種,通過維護實鏈和虛鏈來維護所有路徑之間的關係(類似於樹鏈剖分)。這樣做的目的是為了減少某些鏈上的修改、查詢等操作的複雜度。雖然lct常數巨大。

學lct的大部分都會樹剖吧?我們都知道樹剖維護子樹最大的兒子並形成一條重鏈,由於樹剖是靜態的,所以可以用線段樹來維護。而由於lct需要維護動態的邊,要加邊刪邊。所以需要用更靈活的資料結構來維護,也就是splay(也可以用非旋treap,但是打的人貌似比較少)。

lct將所有的邊分為實邊和虛邊,對於所有的實邊,都有互相連線的邊。而對於虛邊就只有兒子連到父親的邊。我們的splay維護所有的實邊,而剩下的虛邊則可以連線所有的splay。由於我們用splay維護,所以我們可以發現對於所有點x,它的兒子中只有一條實邊。每乙個splay維護的是一條從上到下按在原樹中深度嚴格遞增的路徑,且中序遍歷splay得到的每個點的深度序列嚴格遞增。如圖是一棵splay。接下去lct的講解就以它為例。(紅色為實邊)

lct中有關splay的操作:

void up(int k)

void revers(int k)

void down(int k)

}void rotate(int k)

void splay(int k)

up(k);

}

splay的操作類似於普通的splay,但是又有所不同,比如在進行rotate時我們需要判斷點是否為當前splay的根。而在進行splay操作時,必須時一定要從上往下放標記。

access操作:

access操作是lct的精髓。access(x)的操作是將當前lct的根到x的路徑上的所有邊變為實邊,比如下圖。

我們將從根到黑點的所有邊變為實邊,那麼就必須將一些本來的實邊變為虛邊。

那我們對於每個splay都將x旋轉到根,則x的連向右兒子的邊變為虛邊。並將x的右兒子變成上次access的點,然後上提x(將x變為其父親),繼續進行access操作即可。由於splay的性質,右兒子的深度大於點x,而由於我們已經確定了實邊,剩下的邊都是虛邊,所以將右兒子變為虛邊即可。(刪去x的右兒子,但是fa[右兒子]=x),我們這樣一直往上提,就可以完成access操作。

void access(int k)while(k);

}

makeroot操作:

makeroot(x)操作指的是將點x變為當前lct的根,那我們先access(x),打通x到根的路徑,然後再splay一下,則x就變成了當前splay的根,但是目前的splay是不滿足性質的,因為(當前)深度最小的x在樹根處,而所有的點都是x的左子樹,而實際上所有的點都應該在x的右子樹里(因為深度大於x),所以我們直接將整個區間reverse一下,翻轉一遍就可以滿足splay的性質了。

void makeroot(int k)
findroot操作:

findroot(x)表示x在的splay的樹根。我們先打通x到根的鏈,然後把x旋轉到根,由於我們要找的根深度最小(之前),所以直接一直尋找當前點的左兒子即可。注意在進行findroot時一定要下推標記,不然可能會錯。

int findroot(int k)
split操作:

split(x,y)可以處理出x到y的路徑。我們makeroot(x),然後再access(y),這樣就形成了乙個從x到y路徑的splay,然後我們將y旋轉到根,則y點上的值就是我們要求的路徑的值。

void split(int x,int y)
link操作:

link(x,y)表示連邊(x,y),我們連x和y之前要先判斷一下,如果find(x)==find(y),即x和y在同乙個splay裡,在同乙個聯通塊裡,那麼就直接return,不需要連邊。否則我們先makeroot(x),然後將x的父親變成y即可。

void link(int x,int y)
cut操作:

cut(x,y)表示刪邊(x,y)。我們考慮哪些情況不需要cut,首先如果find(x)!=find(y),肯定不需要cut,因為它們根本不在同乙個聯通塊裡。我們makeroot(x),那麼如果fa[x]!=y那也可以不刪,因為不存在x到y的邊。那如果x與y有邊就一定可以cut嗎?不,如果x有右兒子就不能刪,因為x有右兒子就會意味著x和y之間有別的邊。

void cut(int x,int y)
這些操作做完之後就完成了最基礎的lct操作,下面是luogu上lct模板題的code

#include

#define maxn 300005

using

namespace

std;

int read()

int son[maxn][2],fa[maxn],val[maxn],xyz[maxn],rev[maxn],sta[maxn];

void up(int k)

void revers(int k)

void down(int k)

}int isroot(int k)

void rotate(int k)

void splay(int k)

up(k);

}void access(int k)while(k);

}void makeroot(int k)

int findroot(int k)

void split(int x,int y)

void link(int x,int y)

void cut(int x,int y)

int n,m;

int main()

if(type==1) link(x,y);

if(type==2) cut(x,y);

if(type==3)

}return

0;}

LCT 學習筆記

自己定的學習計畫看起來完不成了 兩天沒學東西,全在補題 決定趕快學點東西 於是就學lct了 link cut tree是一種資料結構,我們用它解決動態樹問題 但是lct不叫動態樹,動態樹是指一類問題 那麼lct的中文名是啥啊 這是 個和 splay 樣只需要寫幾 yi 個 dui 核心函式就能實現一...

LCT 學習筆記

可能叫動態鏈剖分會比較合適?回顧重鏈剖分,我們將 x 所有兒子中子樹 siz 最大的那個兒子欽定為重兒子,乙個結點與它的重兒子的連邊稱為重邊,其餘稱為輕邊。重邊和輕邊形成的鏈把整棵樹剖分成了若干個 dfs 序上的連續段,這樣我們就能使用諸如線段樹等靜態資料結構維護鏈上的資訊了。重剖的侷限性在於它所維...

動態樹(LCT)學習筆記

candy flashhu xzyxzy 想要學lct的還是看這幾篇比較好。我這篇只是總結一些容易理解錯的或者一不小心打錯的地方。lct link cut tree 就是又可以link 動態加邊 又可以cut 動態刪邊 的維護一片森林的資料結構。lct使用實鏈剖分,對每一條實鏈用splay維護 一棵...