题目描述 https://www.luogu.com.cn/problem/P4219
简要题意:给定 $n$ 个点,现在有 $m$ 个操作,操作有两种,第一种操作是给定 $x,y$,加入一条 $(x,y)$ 的无向边,保证任意时刻都为森林;第二种操作是给定 $x,y$,保证 $(x,y)$ 这条边存在,求有多少对点的最短路径经过这条边
Solution 容易发现操作就是连边同时维护子树 $size$,$\rm LCT$ 可以解决这些问题
时间复杂度 $O(n\log n)$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 #include <iostream> #define maxn 100010 using namespace std ;int n, m;#define lc T[i].ch[0] #define rc T[i].ch[1] struct LCT { int ch[2 ], sum, v, val; bool rev; } T[maxn]; int f[maxn]; inline int get (int i) { if (T[f[i]].ch[0 ] == i) return 0 ; if (T[f[i]].ch[1 ] == i) return 1 ; return -1 ; } inline void maintain (int i) { T[i].sum = T[i].val + T[lc].sum + T[rc].sum + T[i].v; }inline void setr (int i) { if (!i) return ; T[i].rev ^= 1 ; swap(lc, rc); } inline void push (int i) { bool &rev = T[i].rev; if (!rev) return ; setr(lc); setr(rc); rev = 0 ; } inline void rotate (int x) { int fa = f[x], ffa = f[f[x]], wx = get(x); if (~get(fa)) T[ffa].ch[T[ffa].ch[1 ] == fa] = x; f[x] = ffa; f[fa] = x; f[T[x].ch[wx ^ 1 ]] = fa; T[fa].ch[wx] = T[x].ch[wx ^ 1 ]; T[x].ch[wx ^ 1 ] = fa; maintain(fa); maintain(x); } void clt (int i) { static int st[maxn], top; st[top = 1 ] = i; while (~get(i)) st[++top] = i = f[i]; while (top) push(st[top--]); } void Splay (int i) { clt(i); for (int fa = f[i]; ~get(i); rotate(i), fa = f[i]) if (~get(fa)) rotate(get(fa) == get(i) ? fa : i); } void access (int i) { for (int p = 0 ; i; i = f[p = i]) { Splay(i); if (rc) T[i].v += T[rc].sum; if (p) T[i].v -= T[p].sum; rc = p; maintain(i); } } inline void make_rt (int i) { access(i); Splay(i); setr(i); }inline void split (int x, int y) { make_rt(x); access(y); Splay(y); }inline void link (int x, int y) { split(x, y); f[x] = y; T[y].v += T[x].sum; maintain(y); } inline void solve_1 () { int x, y; cin >> x >> y; link(x, y); } inline void solve_2 () { int x, y; cin >> x >> y; split(x, y); cout << 1l l * (T[x].v + T[x].val) * (T[y].v + T[y].val) << "\n" ; } int main () { ios::sync_with_stdio(false ); cin .tie(nullptr ); cout .tie(nullptr ); cin >> n >> m; for (int i = 1 ; i <= n; ++i) T[i].val = 1 ; for (int i = 1 ; i <= m; ++i) { char s[10 ]; cin >> s; switch (s[0 ]) { case 'A' : solve_1(); break ; case 'Q' : solve_2(); break ; } } return 0 ; }