Description
Solution
\(LCT\) 维护子树信息,\(son[x]\) 表示 \(x\) 的虚儿子的子树大小,\(siz[x]\) 表示 \(x\) 的实儿子的子树大小。
Code
#include <cstdio>
const int N = 100005;
char opt; int siz[N], son[N], ch[N][2], fa[N], tag[N];
int read() {
int x = 0; char c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9') {
x = (x << 3) + (x << 1) + (c ^ 48);
c = getchar();
}
return x;
}
void swap(int &x, int &y) {
x ^= y, y ^= x, x ^= y;
}
int get(int x) {
return ch[fa[x]][1] == x;
}
int isroot(int x) {
return ch[fa[x]][0] != x && ch[fa[x]][1] != x;
}
void maintain(int x) {
siz[x] = son[x] + siz[ch[x][0]] + siz[ch[x][1]] + 1;
}
void pushdown(int x) {
if (ch[x][0]) tag[ch[x][0]] ^= 1;
if (ch[x][1]) tag[ch[x][1]] ^= 1;
swap(ch[x][0], ch[x][1]), tag[x] = 0;
}
void push(int x) {
if (!isroot(x)) push(fa[x]);
if (tag[x]) pushdown(x);
}
void rotate(int x) {
int y = fa[x], z = fa[y], k = get(x);
if (!isroot(y)) ch[z][ch[z][1]==y] = x;
ch[y][k] = ch[x][k^1], ch[x][k^1] = y;
fa[ch[y][k]] = y, fa[y] = x, fa[x] = z;
maintain(y), maintain(x);
}
void splay(int x) {
push(x);
for (int y; !isroot(x); rotate(x))
if (!isroot(y=fa[x])) rotate(get(x) ^ get(y) ? x : y);
}
void access(int x) { //
for (int y = 0; x; y = x, x = fa[x]) {
splay(x);
son[x] += siz[ch[x][1]] - siz[y];
ch[x][1] = y, maintain(x);
}
}
void makeroot(int x) {
access(x), splay(x), tag[x] ^= 1;
}
void link(int x, int y) { //要access(y), splay(y), 否则y以上的部分不会更新
makeroot(x), access(y), splay(y);
son[y] += siz[x], fa[x] = y, maintain(y);
}
long long query(int x, int y) { //由于access(y)可能会更改根, 因此要splay(x)
makeroot(x), access(y), splay(x);
return 1LL * (son[x] + 1) * (son[y] + 1);
}
int main() {
int n = read(), m = read();
for (int i = 1; i <= n; ++i) siz[i] = 1;
while (m--) {
scanf("%c", &opt);
int x = read(), y = read();
if (opt == 'A') link(x, y);
else printf("%lld\n", query(x, y));
}
return 0;
}