日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Link Cut Tree学习笔记

發(fā)布時(shí)間:2024/8/26 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Link Cut Tree学习笔记 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

捋一下思路

模板題:https://www.luogu.org/problemnew/show/P3690

推薦LCT的教程,個(gè)人認(rèn)為很詳細(xì),本文做了部分引用:https://www.luogu.org/blog/flashblog/solution-p3690

前置知識(shí):Splay

LCT是一種動(dòng)態(tài)樹(shù),支持連邊和斷邊,還有樹(shù)上路徑的查詢

LCT似乎是用Splay維護(hù)深度,這點(diǎn)知道了會(huì)感覺(jué)好理解一些

重要的操作有:

  • access(x),將x到根節(jié)點(diǎn)的路徑上的邊都變成重邊。循環(huán)處理,只有四步——轉(zhuǎn)到根;換兒子;更新信息;當(dāng)前操作點(diǎn)切換為輕邊所指的父親,轉(zhuǎn)第一步

  • makeroot(x),將x變?yōu)樗赟play的根節(jié)點(diǎn)。access操作后x變成Splay內(nèi)深度最大的點(diǎn),然后像Splay一樣把x轉(zhuǎn)上去

  • findroot(x),找所在樹(shù)的原根。不停找左兒子,因?yàn)樽髢鹤泳S護(hù)的深度比當(dāng)前節(jié)點(diǎn)小。

  • split操作。把一個(gè)點(diǎn)轉(zhuǎn)到根節(jié)點(diǎn),原路徑就是另一個(gè)點(diǎn)到根節(jié)點(diǎn)的路徑。然后把下面的點(diǎn)轉(zhuǎn)上去更新答案。

  • link(x, y),使x的父親指向y,連一條輕邊。如果在同一棵樹(shù)則不連邊

  • cut(x, y),使x和y斷邊。使x為根后,y的父親一定指向x,深度相差一定是1。當(dāng)access(y),splay(y)以后,x一定是y的左兒子,直接雙向斷開(kāi)連接。如果不一定存在該邊,先判一下連通性(注意findroot(y)以后x成了根),再看看x,y是否有父子關(guān)系,還要看y是否有左兒子(因?yàn)橐部赡躽的父親還是x,那么其它的點(diǎn)就在y的左子樹(shù)中)。

  • #include <bits/stdc++.h> #define root 0using namespace std;const int maxn = 300010;struct LCT { // 其實(shí)struct Splay會(huì)更好QAQint son[2], fa, val, s;bool tag; }t[maxn]; int st[maxn];bool isroot(int x) {return t[t[x].fa].son[0] == x || t[t[x].fa].son[1] == x; } // 判斷節(jié)點(diǎn)是否是一顆Splay的根,如果是的話返回值是false,不是返回值是true(其實(shí)改成not_root會(huì)更好一些QAQ)void pushup(int x) {t[x].s = t[t[x].son[0]].s ^ t[t[x].son[1]].s ^ t[x].val; }void reverse(int x) {swap(t[x].son[0], t[x].son[1]);t[x].tag ^= 1; }void pushdown(int x) {if(t[x].tag) {if(t[x].son[0]) reverse(t[x].son[0]);if(t[x].son[1]) reverse(t[x].son[1]);t[x].tag = 0;} }void rotate(int x) {int fa = t[x].fa, grandfa = t[t[x].fa].fa, s = t[fa].son[1] == x, tmp = t[x].son[s ^ 1];if(isroot(fa)) {t[grandfa].son[t[grandfa].son[1] == fa] = x;}t[x].son[s ^ 1] = fa;t[fa].son[s] = tmp;if(tmp) {t[tmp].fa = fa;}t[fa].fa = x;t[x].fa = grandfa;pushup(fa); }void pushdown_all(int x) {if(isroot(x)) pushdown_all(t[x].fa);pushdown(x); }void splay(int x) {int fa, grandfa;pushdown_all(x);while(isroot(x)) {fa = t[x].fa, grandfa = t[fa].fa;if(isroot(fa)) rotate((t[fa].son[0] == x) ^ (t[grandfa].son[0] == fa) ? x : fa);rotate(x);// cout << x << " " << fa << " " << grandfa << endl;}pushup(x); } // 以上是splay部分

    下面是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;} } // 將該節(jié)點(diǎn)到該節(jié)點(diǎn)所在Splay的根節(jié)點(diǎn)上的所有路徑都變?yōu)橹剡卛nline void makeroot(int x) {access(x); splay(x);reverse(x); } // 將一個(gè)節(jié)點(diǎn)變成所在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的根節(jié)點(diǎn)inline void split(int x, int y) {makeroot(x);access(y); splay(y); } // 分離出x到y(tǒng)的路徑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; }

    轉(zhuǎn)載于:https://www.cnblogs.com/iycc/p/10440647.html

    總結(jié)

    以上是生活随笔為你收集整理的Link Cut Tree学习笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。