← Home
package main

import (
	"io"
	"os"
	"strconv"
)

var buffer []byte
var pos int

func nextOp() byte {
	for pos < len(buffer) && buffer[pos] <= ' ' {
		pos++
	}
	if pos >= len(buffer) {
		return 0
	}
	res := buffer[pos]
	for pos < len(buffer) && buffer[pos] > ' ' {
		pos++
	}
	return res
}

func nextInt() int {
	for pos < len(buffer) && buffer[pos] <= ' ' {
		pos++
	}
	if pos >= len(buffer) {
		return 0
	}
	res := 0
	for pos < len(buffer) && buffer[pos] > ' ' {
		res = res*10 + int(buffer[pos]-'0')
		pos++
	}
	return res
}

type Query struct {
	op   byte
	arg1 int
	arg2 int
}

type Request struct {
	queryIdx int
	qId      int
	sign     int
}

var (
	office_parent     []int
	office_join_time  []int
	office_val        []int
	office_last_clear []int

	univ_parent []int
	univ_val    []int64
	univ_add    []int64
	univ_size   []int64

	oPath = make([]int, 0, 500005)
	uPath = make([]int, 0, 500005)
)

func find_office(u int) int {
	if office_parent[u] == u {
		return u
	}
	oPath = oPath[:0]
	curr := u
	for office_parent[curr] != curr {
		oPath = append(oPath, curr)
		curr = office_parent[curr]
	}
	root := curr
	for i := len(oPath) - 1; i >= 0; i-- {
		node := oPath[i]
		p := office_parent[node]

		if office_last_clear[p] > office_join_time[node] {
			if office_last_clear[p] > office_val[node] {
				office_val[node] = office_last_clear[p]
			}
		}
		if office_val[p] > office_val[node] {
			office_val[node] = office_val[p]
		}
		if p != root {
			office_join_time[node] = office_join_time[p]
		}
		office_parent[node] = root
	}
	return root
}

func get_max_clear(u int) int {
	root := find_office(u)
	ans := office_val[u]
	if u != root {
		if office_last_clear[root] > office_join_time[u] {
			if office_last_clear[root] > ans {
				ans = office_last_clear[root]
			}
		}
	} else {
		if office_last_clear[root] > ans {
			ans = office_last_clear[root]
		}
	}
	return ans
}

func find_univ(u int) int {
	if univ_parent[u] == u {
		return u
	}
	uPath = uPath[:0]
	curr := u
	for univ_parent[curr] != curr {
		uPath = append(uPath, curr)
		curr = univ_parent[curr]
	}
	root := curr
	for i := len(uPath) - 1; i >= 0; i-- {
		node := uPath[i]
		p := univ_parent[node]
		univ_val[node] += univ_val[p]
		univ_parent[node] = root
	}
	return root
}

func get_univ_add_val(u int) int64 {
	root := find_univ(u)
	if u == root {
		return univ_add[u]
	}
	return univ_val[u] + univ_add[root]
}

func main() {
	buffer, _ = io.ReadAll(os.Stdin)
	n := nextInt()
	m := nextInt()
	if n == 0 {
		return
	}

	queries := make([]Query, m+1)
	for i := 1; i <= m; i++ {
		op := nextOp()
		if op == 'U' || op == 'M' {
			queries[i] = Query{op: op, arg1: nextInt(), arg2: nextInt()}
		} else {
			queries[i] = Query{op: op, arg1: nextInt()}
		}
	}

	office_parent = make([]int, n+1)
	office_join_time = make([]int, n+1)
	office_val = make([]int, n+1)
	office_last_clear = make([]int, n+1)
	for i := 1; i <= n; i++ {
		office_parent[i] = i
	}

	requests := make([][]Request, m+1)
	isQuery := make([]bool, m+1)

	for i := 1; i <= m; i++ {
		q := queries[i]
		if q.op == 'M' {
			rootC := find_office(q.arg1)
			rootD := find_office(q.arg2)
			if rootC != rootD {
				office_parent[rootD] = rootC
				office_join_time[rootD] = i
			}
		} else if q.op == 'Z' {
			rootY := find_office(q.arg1)
			office_last_clear[rootY] = i
		} else if q.op == 'Q' {
			clear_t := get_max_clear(q.arg1)
			requests[clear_t] = append(requests[clear_t], Request{i, q.arg1, -1})
			requests[i] = append(requests[i], Request{i, q.arg1, 1})
			isQuery[i] = true
		}
	}

	univ_parent = make([]int, n+1)
	univ_val = make([]int64, n+1)
	univ_add = make([]int64, n+1)
	univ_size = make([]int64, n+1)
	for i := 1; i <= n; i++ {
		univ_parent[i] = i
		univ_size[i] = 1
	}

	ans := make([]int64, m+1)

	for _, req := range requests[0] {
		ans[req.queryIdx] += int64(req.sign) * get_univ_add_val(req.qId)
	}

	for i := 1; i <= m; i++ {
		q := queries[i]
		if q.op == 'U' {
			rootA := find_univ(q.arg1)
			rootB := find_univ(q.arg2)
			if rootA != rootB {
				univ_val[rootB] = univ_add[rootB] - univ_add[rootA]
				univ_parent[rootB] = rootA
				univ_size[rootA] += univ_size[rootB]
			}
		} else if q.op == 'A' {
			rootX := find_univ(q.arg1)
			univ_add[rootX] += univ_size[rootX]
		}

		for _, req := range requests[i] {
			ans[req.queryIdx] += int64(req.sign) * get_univ_add_val(req.qId)
		}
	}

	out := make([]byte, 0, 1024*1024)
	for i := 1; i <= m; i++ {
		if isQuery[i] {
			out = strconv.AppendInt(out, ans[i], 10)
			out = append(out, '\n')
		}
	}
	os.Stdout.Write(out)
}