Link Cut Tree

LCT 能做什麼?

動態樹問題

給你一座森林

然後加邊、刪邊

過程保證是森林

可能會有一些詢問

LCT 可以做到每次操作均攤 \(O(logN)\)

各種樹上問題

樹鏈剖分能解決的 LCT 也能做,而且通常比較不需要思考,寫起來也比較簡單(?

 

大概就跟看到區間問題無腦亂砸線段樹差不多

Splay

一種平衡二元樹

他可以轉

轉動 : 把自己的深度變淺1,同時維持中序遍歷順序不變

轉法

目前位置是 \(p\)

假設 \(p\) 是左兒子

\(f\) 是 \(p\) 的爸爸

\(c\) 是 \(p\) 的右兒子

 

\(p\) 的爸爸變 \(f\) 的爸爸

\(f\) 成為 \(p\) 的右兒子

\(c\) 變成 \(f\) 的左兒子

轉法

目前位置是 \(p\)

假設 \(p\) 是右兒子

\(f\) 是 \(p\) 的爸爸

\(c\) 是 \(p\) 的左兒子

 

\(p\) 的爸爸變 \(f\) 的爸爸

\(f\) 成為 \(p\) 的左兒子

\(c\) 變成 \(f\) 的右兒子

扣可能長這樣吧

#include <bits/stdc++.h>
#define lc C[p][0]
#define rc C[p][1]
using namespace std;
array<int, 100004> S, F;
array<array<int, 2>, 100004> C;
void pull(int p){
    S[p] = S[lc] + S[rc] + 1;
}
int get(int p){
    return p == C[F[p]][1];
}
void turn(int p){
    int f = F[p], g = get(p), c = C[p][!g];
    if(F[f]) C[F[f]][get(f)] = p;
    F[p] = F[f], F[f] = p, C[p][!g] = f, C[f][g] = c;
    if(c) F[c] = f;
    pull(f), pull(p);
}

Splay

把一個點轉到變成根

爆搜所有情況

轉 \(p\)

爸爸就是根

爆搜所有情況

跟爸爸同邊

轉 \(f\)

轉 \(p\)

爆搜所有情況

跟爸爸不同邊

轉 \(p\)

轉 \(p\)

關於他的扣

void splay(int p){
    for(int f = F[p]; f; turn(p), f = F[p]){
        if(F[f]) turn(get(p) == get(f)? f : p);
    }
}

Splay 的功能

rank(p) : 查 p 在 splay 的中序遍歷中排第幾

find(p, k) : 查 p 所在 splay 中 rank 第 k 的編號

merge(u, v) : 把 u 和 v 兩點所在的兩棵 splay 合併

split(p, k) : 把 p 所在的 splay 從 k 和 k + 1 中間砍斷

相信學過 treap 的大家應該都對這些東西不陌生

然後這4個東西都不會在 LCT 用到

int rank(int p){
    splay(p);
    return S[lc] + 1;
}
int find(int p, int k){
    splay(p);
    while(k){
        if(k > S[lc] + 1) k -= S[lc] + 1, p = rc;
        else if(k <= S[lc]) p = lc;
        else return p;
    }
    return 0;
}
void merge(int u, int v){
    if(!S[u] || !S[v] || find(u, 1) == find(v, 1)) return;
    u = find(u, S[u]), v = find(v, 1);
    splay(u), splay(v);
    C[u][1] = v, F[v] = u;
    pull(u);
}
void split(int p, int k){
    if(!k || !S[p]) return;
    p = find(p, k), splay(p);
    F[rc] = 0, rc = 0;
    pull(p);
}

複雜度

可以用勢能證明 splay 的均攤時間是 \(O(logN)\)

勢能證明

有一個通靈出來的勢能函數 \(\phi(x) = log(|x|(x\) 子樹大小\())\)

均攤複雜度 \(=\) 實際複雜度 \(+\) 總勢能變化

splay 複雜度 \(= \ h(x\) 深度\()\) \(+ \sum\limits_{i = 1}^{t(turn次數)}{\phi(p_i) - \phi(p_{i - 1})}\)

\( = h + \phi(p_t) - \phi(p_0)\)

\(1(\)實際時間\() + \phi(p') + \phi(f') - \phi(p) - \phi(f) \\ = 1 + \phi(f') - \phi(p) \ (\phi(f) = \phi(p')) \\ \le 1 + \phi(p') - \phi(p) \ (\phi(f') \le \phi(p'))\)

\(2(\)實際時間\() + \phi(p') + \phi(f') + \phi(g') - \phi(p) - \phi(f) - \phi(g) \\ = 2 + \phi(f') + \phi(g') - \phi(p) - \phi(f) \ (\phi(g) = \phi(p')) \\ \le 2 + \phi(p') + \phi(g') - 2\phi(p) \ (\phi(f') \le \phi(p'), \phi(f) \ge \phi(p)) \\ \le 3\phi(p') - 3\phi(p) \ (log\frac{|g'| + |p|}{2} \ge \frac{log|g'| + log|p|}{2}) \\ \le 3(\phi(p') - \phi(p)))\)

\(2(\)實際時間\() + \phi(p') + \phi(f') + \phi(g') - \phi(p) - \phi(f) - \phi(g) \\ = 2 + \phi(f') + \phi(g') - \phi(p) - \phi(f) \ (\phi(g) = \phi(p')) \\ \le 2 + \phi(f') + \phi(g') - 2\phi(p) \ (\phi(f) \ge \phi(p)) \\ \le 2\phi(p') - 2\phi(p) \ (log\frac{|f'| + |g'|}{2} \ge \frac{log|f'| + log|g'|}{2}) \\ \le 2(\phi(p') - \phi(p))\)

splay 複雜度 \(\le 3(\phi(p_t) - \phi(p_0)) + 1 \\ \le 3logN + 1 \ (\phi(p_t) = logN) \\ \implies O(logN)\)

一棵翻轉懶標 splay

#include <bits/stdc++.h>
#define lc C[p][0]
#define rc C[p][1]
using namespace std;
array<int, 100004> S, F, rev;
array<array<int, 2>, 100004> C;
void pull(int p){
    S[p] = S[lc] + S[rc] + 1;
}
void push(int p){
    if(rev[p]) swap(lc, rc);
    rev[lc] ^= rev[p], rev[rc] ^= rev[p];
    rev[p] = 0;
}
int get(int p){
    return p == C[F[p]][1];
}
void turn(int p){
    int f = F[p], g = get(p), c = C[p][!g];
    if(F[f]) C[F[f]][get(f)] = p;
    F[p] = F[f], F[f] = p, C[p][!g] = f, C[f][g] = c;
    if(c) F[c] = f;
    pull(f), pull(p);
}
void update(int p){
    if(F[p]) update(F[p]);
    push(p);
}
void splay(int p){
    update(p);
    for(int f = F[p]; f; turn(p), f = F[p]){
        if(F[f]) turn(get(p) == get(f)? f : p);
    }
}
int rank(int p){
    splay(p);
    return S[lc] + 1;
}
int find(int p, int k){
    splay(p);
    while(k){
        push(p);
        if(k > S[lc] + 1) k -= S[lc] + 1, p = rc;
        else if(k <= S[lc]) p = lc;
        else return p;
    }
    return 0;
}
void merge(int u, int v){
    if(!S[u] || !S[v] || find(u, 1) == find(v, 1)) return;
    u = find(u, S[u]), v = find(v, 1);
    splay(u), splay(v);
    C[u][1] = v, F[v] = u;
    pull(u);
}
void split(int p, int k){
    if(!k || !S[p]) return;
    p = find(p, k), splay(p);
    F[rc] = 0, rc = 0;
    pull(p);
}

一點小練習

#include <bits/stdc++.h>
#define lc C[p][0]
#define rc C[p][1]
using namespace std;
array<int, 130004> S, F, rev;
array<array<int, 2>, 130004> C;
void pull(int p){
    S[p] = S[lc] + S[rc] + 1;
}
void push(int p){
    if(rev[p]) swap(lc, rc);
    rev[lc] ^= rev[p], rev[rc] ^= rev[p];
    rev[p] = 0;
}
int get(int p){
    return p == C[F[p]][1];
}
void turn(int p){
    int f = F[p], g = get(p), c = C[p][!g];
    if(F[f]) C[F[f]][get(f)] = p;
    F[p] = F[f], F[f] = p, C[p][!g] = f, C[f][g] = c;
    if(c) F[c] = f;
    pull(f), pull(p);
}
void update(int p){
    if(F[p]) update(F[p]);
    push(p);
}
void splay(int p){
    update(p);
    for(int f = F[p]; f; turn(p), f = F[p]){
        if(F[f]) turn(get(p) == get(f)? f : p);
    }
}
int find(int p, int k){
    splay(p);
    while(k){
        push(p);
        if(k > S[lc] + 1) k -= S[lc] + 1, p = rc;
        else if(k <= S[lc]) p = lc;
        else return p;
    }
    return 0;
}
void merge(int u, int v){
    if(!S[u] || !S[v] || find(u, 1) == find(v, 1)) return;
    u = find(u, S[u]), v = find(v, 1);
    splay(u), splay(v);
    C[u][1] = v, F[v] = u;
    pull(u);
}
void split(int p, int k){
    if(!k || !S[p]) return;
    p = find(p, k), splay(p);
    F[rc] = 0, rc = 0;
    pull(p);
}
void build(int l, int r, int f){
    if(l > r) return;
    int p = (l + r) >> 1;
    F[p] = f, C[f][p > f] = p;
    build(l, p - 1, p), build(p + 1, r, p);
    pull(p);
}
void print(int p){
    if(!p) return;
    push(p);
    print(lc), cout << p << " ", print(rc);
}
signed main(){
    cin.tie(0), cout.tie(0), ios::sync_with_stdio(0);
    int n, q, l1, r1, l2, r2, a, b, c, d, e;
    string t;
    cin >> n >> q;
    build(1, n, 0);
    C[0][1] = 0;
    while(q--){
        cin >> t >> l1 >> r1;
        if(t == "REV"){
            a = find(1, l1 - 1), b = find(1, l1), c = find(1, r1 + 1);
            split(b, r1), split(b, l1 - 1);
            splay(b), rev[b] ^= 1;
            merge(a, b), merge(b, c);
        }else{
            cin >> l2 >> r2;
            a = find(1, l1 - 1), b = find(1, l1), c = find(1, r1 + 1), d = find(1, l2), e = find(1, r2 + 1);
            split(b, r2), split(b, l2 - 1), split(b, r1), split(b, l1 - 1);
            merge(a, d), merge(d, c), merge(c, b), merge(b, e);
        }
    }
    splay(1), print(1), cout << "\n";
    return 0;
}

LCT

用平衡二元樹表示一棵樹

其實跟樹鏈剖分的鏈用 線段樹/treap 差不多

實鏈剖分

回顧樹鏈剖分

實鏈剖分

每個點隨便選一條往下的邊當實邊

每一條實鏈都砸一棵平衡二元樹

於是我們砸了 splay

一棵樹

被砸了splay 之後的樣子

在 splay 中越左邊代表在原樹上越上面

虛邊記父不記子

LCT 最重要的功能

把一個點到樹根中間用實鏈串起來,該點往下都變虛邊

把 2 到根串起來

從 splay 的角度看

int kabab(int p){
    int c;
    for(c = 0; p; c = p, p = F[p]){
        splay(p), rc = c, pull(p);
    }
    return c;
}

回傳 splay 的根

更多功能

把一個點變成根

void plant(int p){
    p = kabab(p);
    rev[p] ^= 1;
}

找原樹上的根

int find(int p){
    p = kabab(p);
    for(; lc; push(p), p = lc);
    return p;
}

把兩個點接起來

void link(int u, int v){
    if(find(u) == find(v)) return;
    if(u > v) swap(u, v);
    E.insert({u, v});
    plant(u), splay(u), F[u] = v;
}

把兩個點斷開來

void cut(int u, int v){
    if(u > v) swap(u, v);
    if(E.find({u, v}) == E.end()) return;
    E.erase({u, v});
    plant(u), kabab(v), splay(u);
    F[C[u][1]] = 0, C[u][1] = 0;
    pull(u);
}

複雜度

用 splay 做的串串操作均攤 \(O(logN)\)

其他種二元平衡樹可能是 \(O(log^2N)\)

串一次合併的鏈數均攤 \(O(logN)\) 條

把兩條鏈串在一起會發生的事情 :

輕虛邊 \(\to\) 輕實邊 or 重虛邊 \(\to\) 重實邊

輕邊最多遇到 \(logN\) 條

重虛邊 \(\to\) 重實邊 \(=\) 重實邊 \(\to\) 重虛邊

重實邊 \(\to\) 重虛邊 \(=\) 輕虛邊 \(\to\) 輕實邊

砸 splay 的複雜度

複雜度 \( = \sum\limits_{i = 1}^{k(串起來的鏈數)}{3(\phi(p_{it}) - \phi(p_{i0})) + 1} \\ \le 3\phi(root) + k \implies O(logN)\)

完整的 LCT

#include <bits/stdc++.h>
#define lc C[p][0]
#define rc C[p][1]
using namespace std;
array<int, 100004> F, S, rev;
array<array<int, 2>, 100004> C;
set<pair<int, int>> E;
int get(int p){
    return p == C[F[p]][1];
}
int root(int p){
    return p != C[F[p]][get(p)];
}
void pull(int p){
    S[p] = S[lc] + S[rc] + 1;
}
void push(int p){
    if(rev[p]) swap(lc, rc);
    rev[lc] ^= rev[p], rev[rc] ^= rev[p];
    rev[p] = 0;
}
void turn(int p){
    int f = F[p], g = get(p), c = C[p][!g];
    if(!root(f)) C[F[f]][get(f)] = p;
    F[p] = F[f], F[f] = p, C[p][!g] = f, C[f][g] = c;
    if(c) F[c] = f;
    pull(f), pull(p);
}
void update(int p){
    if(!root(p)) update(F[p]);
    push(p);
}
void splay(int p){
    update(p);
    for(int f = F[p]; !root(p); turn(p), f = F[p]){
        if(!root(f)) turn(get(p) == get(f)? f : p);
    }
}
int kabab(int p){
    int c;
    for(c = 0; p; c = p, p = F[p]){
        splay(p), rc = c, pull(p);
    }
    return c;
}
void plant(int p){
    p = kabab(p);
    rev[p] ^= 1;
}
int find(int p){
    p = kabab(p);
    for(; lc; push(p), p = lc);
    splay(p);
    return p;
}
void link(int u, int v){
    if(find(u) == find(v)) return;
    if(u > v) swap(u, v);
    E.insert({u, v});
    plant(u), splay(u), F[u] = v;
}
void cut(int u, int v){
    if(u > v) swap(u, v);
    if(E.find({u, v}) == E.end()) return;
    E.erase({u, v});
    plant(u), kabab(v), splay(u);
    F[v] = 0, C[u][1] = 0;
    pull(u);
}

題目

扣點中間就會現身了

#include <bits/stdc++.h>
#define lc C[p][0]
#define rc C[p][1]
using namespace std;
array<int, 100004> F, X, V, rev;
array<array<int, 2>, 100004> C;
set<pair<int, int>> E;
int get(int p){
    return p == C[F[p]][1];
}
int root(int p){
    return p != C[F[p]][get(p)];
}
void pull(int p){
    X[p] = X[lc] ^ X[rc] ^ V[p];
}
void push(int p){
    if(rev[p]) swap(lc, rc);
    rev[lc] ^= rev[p], rev[rc] ^= rev[p];
    rev[p] = 0;
}
void turn(int p){
    int f = F[p], g = get(p), c = C[p][!g];
    if(!root(f)) C[F[f]][get(f)] = p;
    F[p] = F[f], F[f] = p, C[p][!g] = f, C[f][g] = c;
    if(c) F[c] = f;
    pull(f), pull(p);
}
void update(int p){
    if(!root(p)) update(F[p]);
    push(p);
}
void splay(int p){
    update(p);
    for(int f = F[p]; !root(p); turn(p), f = F[p]){
        if(!root(f)) turn(get(p) == get(f)? f : p);
    }
}
int kabab(int p){
    int c;
    for(c = 0; p; c = p, p = F[p]){
        splay(p), rc = c, pull(p);
    }
    return c;
}
void plant(int p){
    p = kabab(p);
    rev[p] ^= 1;
}
int find(int p){
    p = kabab(p);
    for(; lc; push(p), p = lc);
    return p;
}
void link(int u, int v){
    if(find(u) == find(v)) return;
    if(u > v) swap(u, v);
    E.insert({u, v});
    plant(u), splay(u), F[u] = v;
}
void cut(int u, int v){
    if(u > v) swap(u, v);
    if(E.find({u, v}) == E.end()) return;
    E.erase({u, v});
    plant(u), kabab(v), splay(u);
    F[C[u][1]] = 0, C[u][1] = 0;
    pull(u);
}
signed main(){
    int n, q, t, x, y;
    cin >> n >> q;
    for(int i = 1; i <= n; i++) cin >> V[i], X[i]= V[i];
    while(q--){
        cin >> t >> x >> y;
        if(t == 1) link(x, y);
        else if(t == 2) cut(x, y);
        else if(t == 3) splay(x), X[x] ^= V[x] ^ y, V[x] = y;
        else{
            plant(x), kabab(y), splay(x);
            cout << X[x] << "\n";
        }
    }
    return 0;
}

#include <bits/stdc++.h>
#define int unsigned
#define lc C[p][0]
#define rc C[p][1]
using namespace std;
const int mod = 51061;
array<int, 100004> F, S, A, M, val, sum, rev;
array<array<int, 2>, 100004> C;
int add(int a, int b){
    return (a + b) % mod;
}
int mul(int a, int b){
    return a * b % mod;
}
int get(int p){
    return p == C[F[p]][1];
}
int root(int p){
    return p != C[F[p]][get(p)];
}
void pull(int p){
    sum[p] = add(val[p], add(sum[lc], sum[rc]));
    S[p] = S[lc] + S[rc] + 1;
}
void push(int p){
    sum[lc] = add(mul(sum[lc], M[p]), mul(S[lc], A[p]));
    sum[rc] = add(mul(sum[rc], M[p]), mul(S[rc], A[p]));
    val[lc] = add(mul(val[lc], M[p]), A[p]);
    val[rc] = add(mul(val[rc], M[p]), A[p]);
    A[lc] = add(mul(A[lc], M[p]), A[p]);
    A[rc] = add(mul(A[rc], M[p]), A[p]);
    M[lc] = mul(M[lc], M[p]), M[rc] = mul(M[rc], M[p]);
    if(rev[p]) swap(lc, rc);
    rev[lc] ^= rev[p], rev[rc] ^= rev[p];
    A[p] = 0, M[p] = 1, rev[p] = 0;
}
void turn(int p){
    int f = F[p], g = get(p), c = C[p][!g];
    if(!root(f)) C[F[f]][get(f)] = p;
    F[p] = F[f], F[f] = p, C[p][!g] = f, C[f][g] = c;
    if(c) F[c] = f;
    pull(f), pull(p);
}
void update(int p){
    if(!root(p)) update(F[p]);
    push(p);
}
void splay(int p){
    update(p);
    for(int f = F[p]; !root(p); turn(p), f = F[p]){
        if(!root(f)) turn(get(p) == get(f)? f : p);
    }
}
int kabab(int p){
    int c;
    for(c = 0; p; c = p, p = F[p]){
        splay(p), rc = c, pull(p);
    }
    return c;
}
void plant(int p){
    p = kabab(p);
    rev[p] ^= 1;
}
void link(int u, int v){
    plant(u), splay(u), F[u] = v;
}
void cut(int u, int v){
    plant(u), kabab(v), splay(u);
    F[C[u][1]] = 0, C[u][1] = 0;
    pull(u);
}
signed main(){
    char op;
    int n, q, u, v, c;
    cin >> n >> q;
    for(int i = 1; i <= n; i++) sum[i] = val[i] = S[i] = M[i] = 1;
    for(int i = 1; i < n; i++){
        cin >> u >> v;
        link(u, v);
    }
    while(q--){
        cin >> op >> u >> v;
        if(op == '+'){
            cin >> c;
            plant(u), kabab(v), splay(u);
            sum[u] = add(sum[u], mul(S[u], c));
            val[u] = add(val[u], c);
            A[u] = add(A[u], c);
        }else if(op == '-'){
            cut(u, v);
            cin >> u >> v;
            link(u, v);
        }else if(op == '*'){
            cin >> c;
            plant(u), kabab(v), splay(u);
            sum[u] = mul(sum[u], c);
            val[u] = mul(val[u], c);
            A[u] = mul(A[u], c), M[u] = mul(M[u], c);
        }else{
            plant(u), kabab(v), splay(u);
            cout << sum[u] << "\n";
        }
    }
    return 0;
}

這題他媽的有自環

#include <bits/stdc++.h>
#define lc C[p][0]
#define rc C[p][1]
#define pb push_back
using namespace std;
struct edge{
    int p, x;
};
const int inf = 1 << 30;
array<int, 250004> L, R, F, M, V, rev, in;
array<array<int, 2>, 250004> C;
vector<edge> E;
bool cmp(edge a, edge b){
    return a.x < b.x;
}
void pull(int p){
    M[p] = min({V[p], M[lc], M[rc]});
}
void push(int p){
    if(rev[p]) swap(lc, rc);
    rev[lc] ^= rev[p], rev[rc] ^= rev[p];
    rev[p] = 0;
}
int root(int p){
    return p != C[F[p]][0] && p != C[F[p]][1];
}
int get(int p){
    return p == C[F[p]][1];
}
void turn(int p){
    int f = F[p], g = get(p), c = C[p][!g];
    if(!root(f)) C[F[f]][get(f)] = p;
    F[p] = F[f], F[f] = p, C[p][!g] = f, C[f][g] = c;
    if(c) F[c] = f;
    pull(f), pull(p);
}
void update(int p){
    if(!root(p)) update(F[p]);
    push(p);
}
void splay(int p){
    update(p);
    for(int f = F[p]; !root(p); turn(p), f = F[p]){
        if(!root(f)) turn(get(f) == get(p)? f : p);
    }
}
int kabab(int p){
    int c = 0;
    for(; p; c = p, p = F[p]){
        splay(p), rc = c, pull(p);
    }
    return c;
}
void plant(int p){
    p = kabab(p);
    rev[p] ^= 1;
}
int find(int p){
    p = kabab(p);
    for(; lc; push(p), p = lc);
    return p;
}
void link(int u, int v){
    plant(u), splay(u), F[u] = v;
}
void cut(int u, int v){
    plant(u), kabab(v), splay(u);
    F[C[u][1]] = 0, C[u][1] = 0, pull(u);
}
int query(int p){
    splay(p);
    for(; p; push(p), p = M[lc] < M[rc]? lc : rc){
        if(V[p] == M[p]) return p;
    }
    return p;
}
signed main(){
    int n, m, u, v, w, q, ans = inf, cnt = 0;
    cin >> n >> m;
    for(int i = 0; i <= n + m; i++) V[i] = M[i] = inf;
    for(int i = 0, k = n + 1; i < m; i++, k++){
        cin >> u >> v >> w;
        L[k] = u, R[k] = v, V[k] = w;
        E.pb({k, w});
    }
    sort(E.begin(), E.end(), cmp);
    for(int lp = 0, rp = 0; rp < m; rp++){
        auto [p, x] = E[rp];
        if(L[p] == R[p]) continue;
        if(find(L[p]) == find(R[p])){
            plant(L[p]), kabab(R[p]), q = query(L[p]);
            cut(L[q], q), cut(R[q], q), in[q] = 0, cnt--;
        }
        link(L[p], p), link(p, R[p]), in[p] = 1, cnt++;
        while(!in[E[lp].p]) lp++;
        if(cnt == n - 1) ans = min(ans, E[rp].x - E[lp].x);
    }
    cout << ans << "\n";
    return 0;
}

#include <bits/stdc++.h>
#define lc C[p][0]
#define rc C[p][1]
#define int long long
using namespace std;
array<int, 100004> F, S, I, rev;
array<array<int, 2>, 100004> C;
void pull(int p){
    S[p] = S[lc] + S[rc] + 1 + I[p]; 
}
void push(int p){
    if(rev[p]) swap(lc, rc);
    rev[lc] ^= rev[p], rev[rc] ^= rev[p];
    rev[p] = 0;
}
int get(int p){
    return p == C[F[p]][1];
}
int root(int p){
    return p != C[F[p]][0] && p != C[F[p]][1];
}
void turn(int p){
    int f = F[p], g = get(p), c = C[p][!g];
    if(!root(f)) C[F[f]][get(f)] = p;
    F[p] = F[f], F[f] = p, C[p][!g] = f, C[f][g] = c;
    if(c) F[c] = f;
    pull(f), pull(p);
}
void update(int p){
    if(!root(p)) update(F[p]);
    push(p);
}
void splay(int p){
    update(p);
    for(int f = F[p]; !root(p); turn(p), f = F[p]){
        if(!root(f)) turn(get(p) == get(f)? f : p);
    }
}
int kabab(int p){
    int c = 0;
    for(; p; c = p, p = F[p]){
        splay(p), I[p] += S[rc] - S[c], rc = c, pull(p);
    }
    return c;
}
void plant(int p){
    p = kabab(p);
    rev[p] ^= 1;
}
void link(int u, int v){
    plant(u), splay(u), kabab(v), splay(v), F[u] = v, I[v] += S[u];
}
void cut(int u, int v){
    plant(u), kabab(v), splay(u);
    F[C[u][1]]= 0, C[u][1] = 0, pull(u);
}
signed main(){
    char t;
    int n, q, u, v;
    cin >> n >> q;
    for(int i = 1; i <= n; i++) S[i] = 1;
    while(q--){
        cin >> t >> u >> v;
        if(t == 'A') link(u, v);
        else{
            cut(u, v);
            plant(u), plant(v), splay(u), splay(v);
            cout << S[u] * S[v] << "\n";
            link(u, v);
        }
    }
    return 0;
}

#include <bits/stdc++.h>
#define pb push_back
#define lc C[p][0]
#define rc C[p][1]
using namespace std;
struct edge{
    int p, a, b;
};
array<int, 150004> F, M, B, L, R, rev;
array<array<int, 2>, 150004> C;
vector<edge> E;
bool cmp(edge a, edge b){
    return a.a < b.a;
}
int min(int a, int b){
    if(a < 0 || b < 0) return a < 0? b : a;
    return a < b? a : b;
}
void pull(int p){
    M[p] = max({M[lc], M[rc], B[p]});
}
void push(int p){
    if(rev[p]) swap(lc, rc);
    rev[lc] ^= rev[p], rev[rc] ^= rev[p];
    rev[p] = 0;
}
int get(int p){
    return p == C[F[p]][1];
}
int root(int p){
    return p != C[F[p]][0] && p != C[F[p]][1];
}
void turn(int p){
    int f = F[p], g = get(p), c = C[p][!g];
    if(!root(f)) C[F[f]][get(f)] = p;
    F[p] = F[f], F[f] = p, C[p][!g] = f, C[f][g] = c;
    if(c) F[c] = f;
    pull(f), pull(p);
}
void update(int p){
    if(!root(p)) update(F[p]);
    push(p);
}
void splay(int p){
    update(p);
    for(int f = F[p]; !root(p); turn(p), f = F[p]){
        if(!root(f)) turn(get(p) == get(f)? f : p);
    }
}
int kabab(int p){
    int c = 0;
    for(; p; c = p, p = F[p]){
        splay(p), rc = c, pull(p);
    }
    return c;
}
void plant(int p){
    p = kabab(p), rev[p] ^= 1;
}
int find(int p){
    p = kabab(p);
    for(; lc; push(p), p = lc);
    return p;
}
void link(int u, int v){
    plant(u), splay(u), F[u] = v;
}
void cut(int u, int v){
    plant(u), kabab(v), splay(u);
    C[u][1] = 0, F[v] = 0, pull(u);
}
int query(int p){
    splay(p);
    for(; p; push(p), p = M[lc] > M[rc]? lc : rc){
        if(M[p] == B[p]) return p;
    }
    return 0;
}
signed main(){
    int n, m, x, y, p, q, t, ans = -1;
    cin >> n >> m;
    for(int i = n + 1; i <= n + m; i++){
        cin >> x >> y >> p >> q;
        L[i] = x, R[i] = y, B[i] = q;
        E.pb({i, p, q});
    }
    sort(E.begin(), E.end(), cmp);
    for(auto [p, a, b] : E){
        if(L[p] == R[p]) continue;
        if(find(L[p]) == find(R[p])){
            plant(L[p]), kabab(R[p]), t = query(L[p]);
            if(B[t] <= b) continue;
            cut(t, L[t]), cut(t, R[t]);
        }
        link(p, L[p]), link(p, R[p]);
        if(find(1) == find(n)){
            plant(1), kabab(n), splay(1);
            ans = min(ans, a + M[1]);
        }
    }
    cout << ans << "\n";
    return 0;
}

#include <bits/stdc++.h>
#define pb push_back
#define lc C[p][0]
#define rc C[p][1]
using namespace std;
array<int, 300004> F, rev;
array<array<int, 2>, 300004> C;
array<pair<int, int>, 300004> W;
void push(int p){
    if(rev[p]) swap(lc, rc);
    rev[lc] ^= rev[p], rev[rc] ^= rev[p];
    rev[p] = 0;
}
int get(int p){
    return p == C[F[p]][1];
}
int root(int p){
    return p != C[F[p]][0] && p != C[F[p]][1];
}
void turn(int p){
    int f = F[p], g = get(p), c = C[p][!g];
    if(!root(f)) C[F[f]][get(f)] = p;
    F[p] = F[f], F[f] = p, C[p][!g] = f, C[f][g] = c;
    if(c) F[c] = f;
}
void update(int p){
    if(!root(p)) update(F[p]);
    push(p);
}
void splay(int p){
    update(p);
    for(int f = F[p]; !root(p); turn(p), f = F[p]){
        if(!root(f)) turn(get(f) == get(p)? f : p);
    }
}
int kabab(int p){
    int c = 0;
    for(; p; c = p, p = F[p]){
        splay(p), rc = c;
    }
    return c;
}
void plant(int p){
    p = kabab(p);
    rev[p] ^= 1;
}
int find(int p){
    p = kabab(p);
    for(; lc; push(p), p = lc);
    return p;
}
void link(int u, int v){
    plant(u), splay(u), F[u] = v;
}
void cut(int u, int v){
    plant(u), kabab(v), splay(u);
    F[v] = C[u][1] = 0;
}
signed main(){
    int n, m, p, q, k = 1;
    char t;
    cin >> n >> m;
    for(int i = 1; i < n; i++){
        cin >> p >> q;
        link(p, q);
    }
    while(m--){
        cin >> t >> p;
        if(t == 'Q'){
            cin >> q;
            cout << (find(p) == find(q)? "Yes\n" : "No\n");
        }else if(t == 'C'){
            cin >> q;
            W[k++] = {p, q};
            cut(p, q);
        }else{
            auto [a, b] = W[p];
            link(a, b);
        }
    }
    return 0;
}

嗷嗷待補
Made with Slides.com