Link Cut Tree学习笔记
捋一下思路
模板題:https://www.luogu.org/problemnew/show/P3690
推薦LCT的教程,個人認為很詳細,本文做了部分引用:https://www.luogu.org/blog/flashblog/solution-p3690
前置知識:Splay
LCT是一種動態樹,支持連邊和斷邊,還有樹上路徑的查詢
LCT似乎是用Splay維護深度,這點知道了會感覺好理解一些
重要的操作有:
access(x),將x到根節點的路徑上的邊都變成重邊。循環處理,只有四步——轉到根;換兒子;更新信息;當前操作點切換為輕邊所指的父親,轉第一步
makeroot(x),將x變為所在Splay的根節點。access操作后x變成Splay內深度最大的點,然后像Splay一樣把x轉上去
findroot(x),找所在樹的原根。不停找左兒子,因為左兒子維護的深度比當前節點小。
split操作。把一個點轉到根節點,原路徑就是另一個點到根節點的路徑。然后把下面的點轉上去更新答案。
link(x, y),使x的父親指向y,連一條輕邊。如果在同一棵樹則不連邊
cut(x, y),使x和y斷邊。使x為根后,y的父親一定指向x,深度相差一定是1。當access(y),splay(y)以后,x一定是y的左兒子,直接雙向斷開連接。如果不一定存在該邊,先判一下連通性(注意findroot(y)以后x成了根),再看看x,y是否有父子關系,還要看y是否有左兒子(因為也可能y的父親還是x,那么其它的點就在y的左子樹中)。
下面是LCT部分:
inline void access(int x) {for(register int y = root; x; y = x, x = t[x].fa) {// cout << "QAQ" << endl;splay(x);t[x].son[1] = y;pushup(x);// cout << "QAQ" << endl;} } // 將該節點到該節點所在Splay的根節點上的所有路徑都變為重邊inline void makeroot(int x) {access(x); splay(x);reverse(x); } // 將一個節點變成所在Splay的根inline int findroot(int x) {access(x); splay(x);while(t[x].son[0]) {pushdown(x);x = t[x].son[0];}splay(x);return x; } // 找到所在Splay的根節點inline void split(int x, int y) {makeroot(x);access(y); splay(y); } // 分離出x到y的路徑inline void link(int x, int y) {makeroot(x);if(findroot(y) == x) return ;t[x].fa = y; } // 連邊inline void cut(int x, int y) {makeroot(x);if(findroot(y) != x || t[y].fa != x || t[y].son[0]) return ;t[y].fa = t[x].son[1] = 0;pushup(x); } // 斷邊主程序:
int main() {int n = read(), m = read();for(register int i = 1; i <= n; i++) {t[i].val = read();}while(m--) {int opt = read(), x = read(), y = read();if(!opt) {split(x, y);write(t[y].s), putchar(10);}if(opt == 1) {link(x, y);}if(opt == 2) {cut(x, y);}if(opt == 3) {splay(x);t[x].val = y;}}return 0; }轉載于:https://www.cnblogs.com/iycc/p/10440647.html
總結
以上是生活随笔為你收集整理的Link Cut Tree学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: css : 使用浮动实现左右各放一个元
- 下一篇: verilog中timescale