分析
维护子树信息
这里用个 s z 2 sz2 sz2 维护虚子树节点数量
也就是非实子树的数量
需要更新 s z 2 sz2 sz2的地方在, a c c e s s access access 过程中, t r [ x ] . s o n [ 1 ] = p tr[x].son[1]=p tr[x].son[1]=p会修改,此时需要把原来的实边的子树加到虚子树中,更新实子树的答案
同时在 l i n k link link的过程中,存在 t r [ x ] . f a = y tr[x].fa = y tr[x].fa=y,此时对 y y y进行更新,需要把 y y y, s p l a y splay splay到根后进行操作(此处存在坑点)
代码
//P4219
/*
@Author: YooQ
*/
#include <bits/stdc++.h>
using namespace std;
#define sc scanf
#define pr printf
#define ll long long
#define int long long
#define FILE_OUT freopen("out", "w", stdout);
#define FILE_IN freopen("P4219_2.in", "r", stdin);
#define debug(x) cout << #x << ": " << x << "\n";
#define max3(a, b, c) max(a, max(b, c))
#define min3(a, b, c) min(a, min(b, c))
#define AC 0
#define WA 1
#define INF 0x3f3f3f3f
const ll MAX_N = 1e6+5;
const ll MOD = 1e9+7;
int N, M, K;
struct Tr {
int fa, rev, sz, sz2;
int son[2];
}tr[MAX_N];
void push_up(int rt) {
tr[rt].sz = tr[tr[rt].son[0]].sz + tr[tr[rt].son[1]].sz + tr[rt].sz2 + 1;
}
void push_rev(int rt) {
swap(tr[rt].son[0], tr[rt].son[1]);
tr[rt].rev ^= 1;
}
void push_down(int rt) {
if (!tr[rt].rev) return;
int ls = tr[rt].son[0];
int rs = tr[rt].son[1];
if (ls) push_rev(ls);
if (rs) push_rev(rs);
tr[rt].rev ^= 1;
}
bool nroot(int x) {
return tr[tr[x].fa].son[0] == x || tr[tr[x].fa].son[1] == x;
}
bool which(int x) {
return tr[tr[x].fa].son[1] == x;
}
void rotate(int x) {
int p = tr[x].fa;
int q = tr[p].fa;
int side = which(x);
if (nroot(p)) tr[q].son[which(p)] = x;
tr[tr[p].son[side] = tr[x].son[side^1]].fa = p;
tr[tr[x].son[side^1] = p].fa = x;
tr[x].fa = q;
push_up(p); push_up(x);
}
void flush(int x) {
if (nroot(x)) flush(tr[x].fa);
push_down(x);
}
void splay(int x) {
flush(x);
for (int p; nroot(x); rotate(x)) {
if (nroot(p = tr[x].fa)) rotate(which(x) == which(p) ? p : x);
}
}
void access(int x) {
for (int p = 0; x; x = tr[p = x].fa) {
splay(x);
tr[x].sz2 += tr[tr[x].son[1]].sz;
tr[x].sz2 -= tr[tr[x].son[1] = p].sz;
push_up(x);
}
}
int findroot(int x) {
access(x); splay(x);
while (tr[x].son[0]) {
push_down(x);
x = tr[x].son[0];
}
splay(x);
return x;
}
void mkroot(int x) {
access(x); splay(x);
push_rev(x);
}
void split(int x, int y) {
mkroot(x); access(y);
splay(y);
}
void link(int x, int y) {
mkroot(x);
if (findroot(y) == x) return;
splay(y);
tr[tr[x].fa = y].sz2 += tr[x].sz;
push_up(y);
}
void cut(int x, int y) {
mkroot(x);
if (findroot(y) != x || tr[y].fa != x || tr[y].son[0]) return;
tr[y].fa = tr[x].son[1] = 0;
push_up(x);
}
void solve() {
sc("%lld%lld", &N, &M);
char opt[5];
int x, y;
for (int i = 1; i <= N; ++i) {
tr[i].sz = 1;
}
int ans = 0;
for (int i = 1; i <= M; ++i) {
sc("%s", opt);
sc("%lld%lld", &x, &y);
if (*opt == 'A') {
link(x, y);
} else {
// split(x, y);
// pr("%lld\n", (tr[x].sz2 + 1) * (tr[y].sz2 + 1));
cut(x, y);
mkroot(x);
ans = tr[x].sz;
mkroot(y);
ans = tr[y].sz * ans;
link(x, y);
pr("%lld\n", ans);
}
}
}
signed main() {
#ifndef ONLINE_JUDGE
FILE_IN
FILE_OUT
#endif
int T = 1;//cin >> T;
while (T--) solve();
return AC;
}