← Home
package main

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

type FastScanner struct {
	data []byte
	idx  int
	n    int
}

func NewFastScanner() *FastScanner {
	data, _ := io.ReadAll(os.Stdin)
	return &FastScanner{data: data, n: len(data)}
}

func (fs *FastScanner) nextByte() byte {
	for fs.idx < fs.n && fs.data[fs.idx] <= ' ' {
		fs.idx++
	}
	b := fs.data[fs.idx]
	fs.idx++
	return b
}

func (fs *FastScanner) nextInt() int {
	for fs.idx < fs.n && fs.data[fs.idx] <= ' ' {
		fs.idx++
	}
	val := 0
	for fs.idx < fs.n {
		c := fs.data[fs.idx]
		if c < '0' || c > '9' {
			break
		}
		val = val*10 + int(c-'0')
		fs.idx++
	}
	return val
}

type BIT struct {
	tree []int64
	n    int
}

func NewBIT(n int) *BIT {
	return &BIT{tree: make([]int64, n+2), n: n}
}

func (b *BIT) add(i int, v int64) {
	for i <= b.n {
		b.tree[i] += v
		i += i & -i
	}
}

func (b *BIT) point(i int) int64 {
	var res int64
	for i > 0 {
		res += b.tree[i]
		i -= i & -i
	}
	return res
}

func buildIntervals(n, tot int, left, right []int32, roots []int32) ([]int32, []int32, []int32) {
	l := make([]int32, tot+1)
	r := make([]int32, tot+1)
	pos := make([]int32, n+1)
	stackU := make([]int32, 0, tot*2)
	stackS := make([]byte, 0, tot*2)
	var cnt int32
	n32 := int32(n)

	for _, root := range roots {
		stackU = append(stackU, root)
		stackS = append(stackS, 0)
		for len(stackU) > 0 {
			u := stackU[len(stackU)-1]
			st := stackS[len(stackS)-1]
			stackU = stackU[:len(stackU)-1]
			stackS = stackS[:len(stackS)-1]

			if st == 0 {
				stackU = append(stackU, u)
				stackS = append(stackS, 1)
				if u > n32 {
					ru := right[u]
					lu := left[u]
					if ru != 0 {
						stackU = append(stackU, ru)
						stackS = append(stackS, 0)
					}
					if lu != 0 {
						stackU = append(stackU, lu)
						stackS = append(stackS, 0)
					}
				}
			} else {
				if u <= n32 {
					cnt++
					l[u] = cnt
					r[u] = cnt
					pos[u] = cnt
				} else {
					l[u] = l[left[u]]
					r[u] = r[right[u]]
				}
			}
		}
	}

	return l, r, pos
}

func updateMax(seg []int32, size int, l, r, val int32) {
	li := int(l) - 1 + size
	ri := int(r) - 1 + size
	for li <= ri {
		if li&1 == 1 {
			if seg[li] < val {
				seg[li] = val
			}
			li++
		}
		if ri&1 == 0 {
			if seg[ri] < val {
				seg[ri] = val
			}
			ri--
		}
		li >>= 1
		ri >>= 1
	}
}

func queryMax(seg []int32, size int, p int32) int32 {
	i := int(p) - 1 + size
	var res int32
	for i > 0 {
		if res < seg[i] {
			res = seg[i]
		}
		i >>= 1
	}
	return res
}

func main() {
	fs := NewFastScanner()
	n := fs.nextInt()
	m := fs.nextInt()

	maxNodes := 2*n + 5

	leftUni := make([]int32, maxNodes)
	rightUni := make([]int32, maxNodes)
	leftOff := make([]int32, maxNodes)
	rightOff := make([]int32, maxNodes)
	sizeUni := make([]int32, maxNodes)

	currentUni := make([]int32, n+1)
	currentOff := make([]int32, n+1)

	for i := 1; i <= n; i++ {
		currentUni[i] = int32(i)
		currentOff[i] = int32(i)
		sizeUni[i] = 1
	}

	uniAddNode := make([]int32, m+1)
	uniAddVal := make([]int64, m+1)
	raidNode := make([]int32, m+1)
	queryIdAtTime := make([]int32, m+1)
	queryDorm := make([]int32, m+1)

	uniTot := n
	offTot := n
	qcnt := 0

	for t := 1; t <= m; t++ {
		op := fs.nextByte()
		switch op {
		case 'U':
			a := fs.nextInt()
			b := fs.nextInt()
			uniTot++
			na := currentUni[a]
			nb := currentUni[b]
			leftUni[uniTot] = na
			rightUni[uniTot] = nb
			sizeUni[uniTot] = sizeUni[na] + sizeUni[nb]
			currentUni[a] = int32(uniTot)
			currentUni[b] = 0
		case 'M':
			c := fs.nextInt()
			d := fs.nextInt()
			offTot++
			nc := currentOff[c]
			nd := currentOff[d]
			leftOff[offTot] = nc
			rightOff[offTot] = nd
			currentOff[c] = int32(offTot)
			currentOff[d] = 0
		case 'A':
			x := fs.nextInt()
			node := currentUni[x]
			uniAddNode[t] = node
			uniAddVal[t] = int64(sizeUni[node])
		case 'Z':
			y := fs.nextInt()
			raidNode[t] = currentOff[y]
		case 'Q':
			q := fs.nextInt()
			qcnt++
			queryIdAtTime[t] = int32(qcnt)
			queryDorm[qcnt] = int32(q)
		}
	}

	rootsOff := make([]int32, 0, n)
	for i := 1; i <= n; i++ {
		if currentOff[i] != 0 {
			rootsOff = append(rootsOff, currentOff[i])
		}
	}

	lOff, rOff, posOff := buildIntervals(n, offTot, leftOff, rightOff, rootsOff)

	sizeSeg := 1
	for sizeSeg < n {
		sizeSeg <<= 1
	}
	seg := make([]int32, sizeSeg<<1)

	lastRaid := make([]int32, qcnt+1)

	for t := 1; t <= m; t++ {
		if node := raidNode[t]; node != 0 {
			updateMax(seg, sizeSeg, lOff[node], rOff[node], int32(t))
		}
		if qid := queryIdAtTime[t]; qid != 0 {
			lastRaid[qid] = queryMax(seg, sizeSeg, posOff[queryDorm[qid]])
		}
	}

	rootsUni := make([]int32, 0, n)
	for i := 1; i <= n; i++ {
		if currentUni[i] != 0 {
			rootsUni = append(rootsUni, currentUni[i])
		}
	}

	lUni, rUni, posUni := buildIntervals(n, uniTot, leftUni, rightUni, rootsUni)

	headReq := make([]int32, m+1)
	reqCap := 2*qcnt + 5
	reqNext := make([]int32, reqCap)
	reqQid := make([]int32, reqCap)
	reqCoef := make([]int8, reqCap)
	reqCnt := 0

	for t := 1; t <= m; t++ {
		if qid := queryIdAtTime[t]; qid != 0 {
			reqCnt++
			reqNext[reqCnt] = headReq[t]
			headReq[t] = int32(reqCnt)
			reqQid[reqCnt] = qid
			reqCoef[reqCnt] = 1

			if r := lastRaid[qid]; r != 0 {
				reqCnt++
				reqNext[reqCnt] = headReq[r]
				headReq[r] = int32(reqCnt)
				reqQid[reqCnt] = qid
				reqCoef[reqCnt] = -1
			}
		}
	}

	bit := NewBIT(n)
	ans := make([]int64, qcnt+1)

	for t := 1; t <= m; t++ {
		if node := uniAddNode[t]; node != 0 {
			l := int(lUni[node])
			r := int(rUni[node])
			v := uniAddVal[t]
			bit.add(l, v)
			if r < n {
				bit.add(r+1, -v)
			}
		}
		for e := headReq[t]; e != 0; e = reqNext[e] {
			qid := reqQid[e]
			val := bit.point(int(posUni[queryDorm[qid]]))
			ans[qid] += int64(reqCoef[e]) * val
		}
	}

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