日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

Link Cut Tree学习笔记

發布時間:2024/8/26 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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的左子樹中)。

  • #include <bits/stdc++.h> #define root 0using namespace std;const int maxn = 300010;struct LCT { // 其實struct Splay會更好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; } // 判斷節點是否是一顆Splay的根,如果是的話返回值是false,不是返回值是true(其實改成not_root會更好一些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;} } // 將該節點到該節點所在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学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。