WA 的地方大概在 10000+ 行,有一些是 too short ,有一些是答案错了。
思路是线段树粉质,可撤销并查集统计连通块大小。
#include <bits/stdc++.h>
using namespace std;
#define ri register int
#define ll long long
inline void porn(){ ios::sync_with_stdio(0),cout.tie(0),cin.tie(0); }
#define Tp template<class T>
#define g() getchar()
#define pc(x) putchar(x)
#define isd(x) (x>=48&&x<=57)
namespace SlowIO{
Tp inline void rd(T &x){ x=0; char i=g(); bool f=1; while(!isd(i)) f&=(i!='-'),i=g(); while(isd(i)) x=(x<<3)+(x<<1)+(i^48),i=g(); x*=((f<<1)-1); }
const int OUT=1e6; static char outp[OUT]; int out;
Tp inline void op(T x){ out=0; x<0&&(x=-x,pc('-')); if(!x){ pc(48); return; } while(x) outp[++out]=x%10+48,x/=10; while(out) pc(outp[out--]); }
Tp inline void writeln(T x){ op(x);pc('\n'); }
Tp inline void writesp(T x){ op(x); pc(' '); }
Tp inline void write(T x,char c=0){ op(x); c&&pc(c); }
}; using namespace SlowIO;
//负载:如果删除 (x,y) ,此时两边的连通块大小之积
//那你就把所有关于 (x,y) 的询问挑出来,除了这些时间,>= occurrence time 的时间都包含这条边,所有这种区间个数是 O(m)
//然后就用可撤销冰茶鸡统计连通块大小即可。复杂度是 O(n \log^2 n) 。
#define N 100003
#define swp(a,b) (a^=b^=a^=b)
#define emp emplace_back
#define pii pair<int,int>
int n,q,fa[N],siz[N],wgt[N],top;
struct Stacknode{ int a,ds; bool dw; }sta[N];
struct Data{ bool chg; pii e; }a[N];
vector<pii > vec[N<<2]; ll ans[N];
pii b[N]; int Id[N],lst[N],cnt; //用来给每条边分配编号
inline void Getfa(int n){ for(ri i=1;i<=n;++i) fa[i]=i,siz[i]=wgt[i]=1; }
inline int Find(int x){ while(fa[x]^x) x=fa[x]; return x; }
inline void Merge(int a,int b){ wgt[a]>wgt[b]&&swp(a,b); fa[sta[++top].a=a]=b,siz[b]+=(sta[top].ds=siz[a]),wgt[b]+=(sta[top].dw=wgt[a]==wgt[b]); }
inline void insert(int u,int l,int r,int L,int R,pii x){
if(l>=L&&r<=R) return vec[u].emp(x); ri mid=l+r>>1;
if(L<=mid) insert(u<<1,l,mid,L,R,x); if(R>mid) insert(u<<1|1,mid+1,r,L,R,x);
}
inline void Calc(int id){ if(a[id].chg) return; ans[id]=1ll*siz[Find(a[id].e.first)]*siz[Find(a[id].e.second)]; }
inline void Dfs(int u,int l,int r){
int Stop=top;
for(pii t:vec[u]){
int f1=Find(t.first),f2=Find(t.second);
if(f1==f2) continue; Merge(f1,f2);
} auto Cls=[](int lst){
while(top^lst) siz[fa[sta[top].a]]-=sta[top].ds,
wgt[fa[sta[top].a]]-=sta[top].dw,fa[sta[top].a]=sta[top].a,--top;
}; if(l==r) return Calc(l),Cls(Stop);
ri mid=l+r>>1; Dfs(u<<1,l,mid),Dfs(u<<1|1,mid+1,r),Cls(Stop);
}
int main()
{
rd(n),rd(q); Getfa(n);
for(ri i=1;i<=q;++i){
char inp=g(); while(inp<'A'||inp>'Q') inp=g();
int x,y; rd(x),rd(y); if(inp=='A') b[++cnt]={min(x,y),max(x,y)},a[i]={1,{min(x,y),max(x,y)}}; //为防止 (y,x) 和 (x,y) 引起错误直接固定前小后大
else a[i]={0,{min(x,y),max(x,y)}};
} sort(b+1,b+cnt+1); for(ri i=1;i<=q;++i){
Id[i]=lower_bound(b+1,b+cnt+1,a[i].e)-b;
if(a[i].chg){ lst[Id[i]]=i; continue; }
insert(1,1,q,lst[Id[i]],i-1,a[i].e),lst[Id[i]]=i+1;
} for(ri i=1;i<=q;++i) if(lst[Id[i]]!=n+1) insert(1,1,q,lst[Id[i]],n,a[i].e),lst[Id[i]]=n+1; //除了询问这条边外的所有时间都有这条边
Dfs(1,1,q); for(ri i=1;i<=q;++i) if(!a[i].chg) writeln(ans[i]);
return 0;
}