这算是“边带权并查集”的模板题吧。
为了方便(按照自己习惯来),规定有向边$d[x]$为x指向父亲的边的权值。
这题的$d[x]$就是父亲与自己的距离,若采用路径压缩的话,就是$x$到集合的根的距离。
路径压缩时:

int get(int x)
{
    if(x==fa[x])return x;
    int root=get(fa[x]);
    d[x]+=d[fa[x]];//fa[x]与x的距离+root到fa[x]的距离 
    return fa[x]=root;
}

那么关于询问($x,y$),首先要判断其是否在同一个集合。若在同一个集合,$abs(d[y]-d[x])-1$即为答案。
关于合并$(x,y)$所在集合,已经规定了有向性,那么$x$的根$p$到$y$的根$q$的距离就为$y$集合中的元素个数。
其他很好理解了。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#define gc getchar()
using namespace std;
const int N=30005;
inline void qr(int &x)
{
    x=0;char c=gc;int f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
    while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
    x*=f;
}
void qw(int x)
{
    if(x<0)putchar('-'),x=-x;
    if(x/10)qw(x/10);
    putchar(x%10+48);
}
int fa[N],d[N],size[N];
int get(int x)
{
    if(x==fa[x])return x;
    int root=get(fa[x]);
    d[x]+=d[fa[x]];//fa[x]与x的距离+root到fa[x]的距离 
    return fa[x]=root;
}
void merge(int x,int y)
{
    x=get(x),y=get(y);
    fa[x]=y;d[x]=size[y];
    size[y]+=size[x];
}
int main()
{
    //freopen("5.in","r",stdin);
    int n;qr(n);
    for(int i=1;i<=30000;i++)fa[i]=i,size[i]=1;
    for(int i=1;i<=n;i++)
    {
        char s[3];int x,y;scanf("%s",s+1);qr(x),qr(y);
        if(s[1]=='M')merge(x,y);
        else
        {
            int fx=get(x),fy=get(y);
            if(fx==fy)
            {
                qw(abs(d[y]-d[x])-1);puts("");
            }
            else  puts("-1");
        }
    }
    return 0;
}