#include <bits/stdc++.h>
using namespace std;
const int MAXN = 500005;
int N, M, Qlen;
struct data {
  char op;
  int x, y;
} D[MAXN];
struct query {
  int x, tim;
  query(int x = 0, int tim = 0) : x(x), tim(tim) {}
} Q[MAXN];
bool cmp(query q1, query q2) { return q1.tim < q2.tim; }
long long ans[MAXN];
struct segmentTreeAdd {
  long long add[MAXN * 12];
  void addit(int o, long long k) { add[o] += k; }
  void Add(int o, int l, int r, int L, int R, long long k) {
    if (r < L || l > R) return;
    if (L <= l && r <= R) return addit(o, k);
    Add((o << 1), l, ((l + r) >> 1), L, R, k),
        Add((o << 1 | 1), ((l + r) >> 1) + 1, r, L, R, k);
  }
  long long qv(int o, int l, int r, int pos) {
    if (l == r) return add[o];
    if (pos <= ((l + r) >> 1))
      return add[o] + qv((o << 1), l, ((l + r) >> 1), pos);
    else
      return add[o] + qv((o << 1 | 1), ((l + r) >> 1) + 1, r, pos);
  }
} sgt1;
struct segmentTreeCov {
  int val[MAXN * 12], cov[MAXN * 12];
  void cover(int o, long long k) { val[o] = k, cov[o] = k; }
  void pushdown(int o) {
    if (cov[o])
      cover((o << 1), cov[o]), cover((o << 1 | 1), cov[o]), cov[o] = 0;
  }
  void Cov(int o, int l, int r, int L, int R, int k) {
    if (r < L || l > R) return;
    if (L <= l && r <= R) return cover(o, k);
    pushdown(o), Cov((o << 1), l, ((l + r) >> 1), L, R, k),
        Cov((o << 1 | 1), ((l + r) >> 1) + 1, r, L, R, k);
  }
  int qv(int o, int l, int r, int pos) {
    if (l == r) return val[o];
    pushdown(o);
    if (pos <= ((l + r) >> 1))
      return qv((o << 1), l, ((l + r) >> 1), pos);
    else
      return qv((o << 1 | 1), ((l + r) >> 1) + 1, r, pos);
  }
} sgt2;
struct kruskal {
  int cnt, fa[MAXN * 3], siz[MAXN * 3], sum[MAXN * 3], dfn[MAXN * 3], dfncnt;
  struct node {
    int v, next;
  } E[MAXN * 3];
  int head[MAXN * 3], Elen;
  void init(int n, int m) {
    cnt = n;
    for (int i = 1; i <= n + m; ++i) fa[i] = i;
  }
  void add(int u, int v) {
    ++Elen, E[Elen].v = v, E[Elen].next = head[u], head[u] = Elen;
  }
  int get(int x) {
    if (fa[x] != x) fa[x] = get(fa[x]);
    return fa[x];
  }
  void merge(int x, int y) {
    ++cnt, add(get(cnt), get(x)), add(get(cnt), get(y));
    fa[get(x)] = get(cnt), fa[get(y)] = get(cnt);
  }
  void dfs(int u) {
    dfn[u] = ++dfncnt, siz[u] = 1, sum[u] = u <= N;
    for (int i = head[u]; i; i = E[i].next) {
      dfs(E[i].v), sum[u] += sum[E[i].v], siz[u] += siz[E[i].v];
    }
  }
} T1, T2;
int main() {
  scanf("%d%d", &N, &M);
  char op[2];
  T1.init(N, M), T2.init(N, M);
  for (int i = 1; i <= M; ++i) {
    scanf("%s%d", &D[i].op, &D[i].x);
    if (D[i].op == 'U') {
      scanf("%d", &D[i].y);
      T1.merge(D[i].x, D[i].y);
    } else if (D[i].op == 'M') {
      scanf("%d", &D[i].y);
      T2.merge(D[i].x, D[i].y);
    } else if (D[i].op == 'A') {
      D[i].x = T1.get(D[i].x);
    } else if (D[i].op == 'Z') {
      D[i].x = T2.get(D[i].x);
    }
  }
  for (int i = 1; i <= T1.cnt; ++i)
    if (T1.fa[i] == i) T1.dfs(i);
  for (int i = 1; i <= T2.cnt; ++i)
    if (T2.fa[i] == i) T2.dfs(i);
  for (int i = 1; i <= M; ++i) {
    if (D[i].op == 'Z') {
      sgt2.Cov(1, 1, T2.cnt, T2.dfn[D[i].x],
               T2.dfn[D[i].x] + T2.siz[D[i].x] - 1, i);
    } else if (D[i].op == 'Q') {
      Q[++Qlen] = query(i, sgt2.qv(1, 1, T2.cnt, T2.dfn[D[i].x]));
    }
  }
  sort(Q + 1, Q + Qlen + 1, cmp);
  for (int i = 0, j = 1; i <= M; ++i) {
    if (i) {
      if (D[i].op == 'A') {
        sgt1.Add(1, 1, T1.cnt, T1.dfn[D[i].x],
                 T1.dfn[D[i].x] + T1.siz[D[i].x] - 1, T1.sum[D[i].x]);
      } else if (D[i].op == 'Q') {
        ans[i] += sgt1.qv(1, 1, T1.cnt, T1.dfn[D[i].x]);
      }
    }
    for (; j <= Qlen && Q[j].tim == i; ++j) {
      ans[Q[j].x] -= sgt1.qv(1, 1, T1.cnt, T1.dfn[D[Q[j].x].x]);
    }
  }
  for (int i = 1; i <= M; ++i)
    if (D[i].op == 'Q') printf("%lld\n", ans[i]);
  return 0;
}
