朴素的LCT是不维护虚边以及轻儿子的。
但是这道题需要动态维护这么一个子树大小,就可以考虑维护一下虚边。
一个节点x,维护两个:虚儿子的子树大小之和,以及整棵子树大小。
然后这题就结束了。注意long long。
这辈子都不可能写真正的top-tree的。只能写写伪top-tree这样来维持一下生计。
#include <cstdio>
#include <algorithm>
#define N 100010
#define pa fa[x]
#define lc ch[x][0]
#define rc ch[x][1]
using namespace std;
inline char gc() {
static char now[1<<16], *S, *T;
if(S == T) {T = (S = now) + fread(now, 1, 1<<16, stdin); if(S == T) return EOF;}
return *S++;
}
inline int read() {
int x = 0; char c = gc();
while(c < '0' || c > '9') c = gc();
while(c >= '0' && c <= '9') {x = x * 10 + c - 48; c = gc();}
return x;
}
int ch[N][2], fa[N], sz[N], sum[N], rev[N];
inline void update(int x) {sum[x] = sum[ch[x][0]] + sum[ch[x][1]] + sz[x] + 1;}
inline void rever(int x) {rev[x]^= 1; swap(ch[x][0], ch[x][1]);}
inline void pushdown(int x) {
if(rev[x]) {
if(lc) rever(lc);
if(rc) rever(rc);
rev[x] = 0;
}
}
inline bool isr(int x) {return ch[pa][0] != x && ch[pa][1] != x;}
void pd(int x) {if(!isr(x)) pd(pa); pushdown(x);}
inline bool wh(int x) {return ch[pa][1] == x;}
inline void rotate(int x) {
int y = fa[x], z = fa[y], c = wh(x);
if(!isr(y)) ch[z][wh(y)] = x;
fa[x] = z;
ch[y][c] = ch[x][c^1]; fa[ch[x][c^1]] = y;
ch[x][c^1] = y; fa[y] = x;
update(y); update(x);
}
inline void splay(int x) {
pd(x);
for(; !isr(x); rotate(x))
if(!isr(pa)) rotate(wh(pa) == wh(x) ? pa : x);
}
inline void access(int x) {
for(int y = 0; x; y = x, x = pa) {
splay(x);
sz[x]+= sum[rc] - sum[y];
rc = y, update(x);
}
}
inline void maker(int x) {
access(x); splay(x); rever(x);
}
inline void link(int x, int y) {
maker(x); access(y); splay(y);
fa[x] = y; sz[y]+= sum[x]; update(y);
}
int n, q;
int main() {
n = read(); q = read();
for(int i = 1; i <= n; ++i) sum[i] = 1;
for(int i = 1; i <= q; ++i) {
char opt = gc(); while(opt != 'A' && opt != 'Q') opt = gc(); int x = read(), y = read();
if(opt == 'A') link(x, y);
else {maker(x); access(y); splay(x); printf("%lld\n", (long long)sum[y] * (sum[x] - sum[y]));}
}
return 0;
}