动态连边,可以lct做。容易看出通过一条边的简单路径数量就是在lct上分别以两个端点为根的树的总大小(除去以另一个节点为根的子树总大小)相乘,但普通lct只能维护节点的重链连接的子树大小,所以这里要开两个变量,x2维护一个节点所有轻链连接的子树大小,x1维护以该节点为根的树的总大小。
x1=左子树的x1+右子树的x1+1+节点的x2。和普通lct的更新差不多。至于何时更新x2,应该是只有边的轻重发生变化时才需要更新。所以access操作时,把p节点转到根后,在换儿子之前要先把p的x2减去它新的右儿子的x1,加上旧右儿子的x1。link操作时,两个节点都需要转到根,若是u父亲为v,v的x2要加上u的x1。
最后split(u,v),输出(v.x1-u.x1)*u.x1就是答案了。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100010;
struct node{
int l,r,fa,x1,x2;
bool rev;
}tree[N];
int n,m,q[N];
char str1[5];
inline int read(){
int x=0,f=0;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return f?-x:x;
}
inline void update(int p){
tree[p].x1=tree[tree[p].l].x1+tree[tree[p].r].x1+1+tree[p].x2;
}
inline void new1(int p){
swap(tree[p].l,tree[p].r);
tree[p].rev=!tree[p].rev;
}
inline void pushdown(int p){
if(tree[p].rev){
new1(tree[p].l);new1(tree[p].r);
tree[p].rev=false;
}
}
inline bool nroot(int p){
return tree[tree[p].fa].l==p||tree[tree[p].fa].r==p;
}
inline void left_rotate(int p){
int q=tree[p].fa,r=tree[q].fa;
tree[q].r=tree[p].l;
if(tree[p].l)tree[tree[p].l].fa=q;
if(nroot(q)){
if(tree[r].l==q)tree[r].l=p;
else tree[r].r=p;
}
tree[q].fa=p;tree[p].l=q;tree[p].fa=r;
update(q);update(p);
}
inline void right_rotate(int p){
int q=tree[p].fa,r=tree[q].fa;
tree[q].l=tree[p].r;
if(tree[p].r)tree[tree[p].r].fa=q;
if(nroot(q)){
if(tree[r].l==q)tree[r].l=p;
else tree[r].r=p;
}
tree[q].fa=p;tree[p].r=q;tree[p].fa=r;
update(q);update(p);
}
inline bool getlr(int p){
return tree[tree[p].fa].l==p;
}
inline void rotate(int p){
if(getlr(p))right_rotate(p);
else left_rotate(p);
}
inline void splay(int p){
int cnt=0;q[++cnt]=p;
for(int i=p;nroot(i);i=tree[i].fa)q[++cnt]=tree[i].fa;
while(cnt)pushdown(q[cnt--]);
while(nroot(p)){
int q=tree[p].fa;
if(nroot(q)){
if(getlr(q)==getlr(p))rotate(q);
else rotate(p);
}rotate(p);
}
}
inline void access(int p){
for(int x=0;p;x=p,p=tree[p].fa){
splay(p);tree[p].x2=tree[p].x2-tree[x].x1+tree[tree[p].r].x1;
tree[p].r=x;update(p);
}
}
inline void makeroot(int p){
access(p);splay(p);new1(p);
}
inline void split(int x,int y){
makeroot(x);access(y);splay(y);
}
inline void link(int x,int y){
makeroot(x);makeroot(y);tree[x].fa=y;tree[y].x2+=tree[x].x1;
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++){
tree[i].l=tree[i].r=tree[i].fa=0;
tree[i].x1=1;tree[i].x2=0;tree[i].rev=false;
}
for(int u,v,i=1;i<=m;i++){
scanf("%s",str1);u=read();v=read();
if(str1[0]=='A')link(u,v);
else{
split(u,v);
printf("%lld\n",1ll*(tree[v].x1-tree[u].x1)*tree[u].x1);
}
}
return 0;
}