← Home
package main

import (
	"os"
)

type Edge struct {
	u, v int32
}

type EdgeList struct {
	e    Edge
	next int32
}

const (
	AddA    = 1
	AddAUB  = 2
	AddBoth = 3
)

var pool []EdgeList
var headA []int32
var headAUB []int32

func addEdgeNode(node int, e Edge, tpe int) {
	if tpe&AddA != 0 {
		idx := int32(len(pool))
		pool = append(pool, EdgeList{e, headA[node]})
		headA[node] = idx
	}
	if tpe&AddAUB != 0 {
		idx := int32(len(pool))
		pool = append(pool, EdgeList{e, headAUB[node]})
		headAUB[node] = idx
	}
}

func addEdge(node, L, R, l, r int, e Edge, tpe int) {
	if l <= L && R <= r {
		addEdgeNode(node, e, tpe)
		return
	}
	mid := L + (R - L)/2
	if l <= mid {
		addEdge(node*2, L, mid, l, r, e, tpe)
	}
	if r > mid {
		addEdge(node*2+1, mid+1, R, l, r, e, tpe)
	}
}

type DSUState struct {
	u int32
	v int32
}

type DSU struct {
	parent  []int32
	size    []int32
	comps   int32
	history []DSUState
}

func NewDSU(n int32) *DSU {
	d := &DSU{
		parent:  make([]int32, n+1),
		size:    make([]int32, n+1),
		comps:   n,
		history: make([]DSUState, 0, n),
	}
	for i := int32(1); i <= n; i++ {
		d.parent[i] = i
		d.size[i] = 1
	}
	return d
}

func (d *DSU) Find(i int32) int32 {
	for d.parent[i] != i {
		i = d.parent[i]
	}
	return i
}

func (d *DSU) Merge(u, v int32) {
	rootU := d.Find(u)
	rootV := d.Find(v)
	if rootU != rootV {
		if d.size[rootU] < d.size[rootV] {
			rootU, rootV = rootV, rootU
		}
		d.parent[rootV] = rootU
		d.size[rootU] += d.size[rootV]
		d.comps--
		d.history = append(d.history, DSUState{rootU, rootV})
	}
}

func (d *DSU) Rollback(target int) {
	for len(d.history) > target {
		state := d.history[len(d.history)-1]
		d.history = d.history[:len(d.history)-1]

		d.parent[state.v] = state.v
		d.size[state.u] -= d.size[state.v]
		d.comps++
	}
}

func main() {
	buf, _ := os.ReadFile("/dev/stdin")
	pos := 0

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

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

	n := nextInt()
	q := nextInt()
	if q == 0 {
		return
	}

	headA = make([]int32, 4*q+1)
	headAUB = make([]int32, 4*q+1)
	for i := range headA {
		headA[i] = -1
		headAUB[i] = -1
	}
	pool = make([]EdgeList, 0, 32000000)

	mapA := make(map[Edge]int)
	mapB := make(map[Edge]int)

	for i := 0; i < int(q); i++ {
		c := nextChar()
		u := nextInt()
		v := nextInt()
		if u > v {
			u, v = v, u
		}
		e := Edge{u, v}

		if c == 'A' {
			if start, ok := mapA[e]; ok {
				addEdge(1, 0, int(q)-1, start, i-1, e, AddBoth)
				delete(mapA, e)
			} else {
				mapA[e] = i
			}
		} else if c == 'B' {
			if start, ok := mapB[e]; ok {
				addEdge(1, 0, int(q)-1, start, i-1, e, AddAUB)
				delete(mapB, e)
			} else {
				mapB[e] = i
			}
		}
	}

	for e, start := range mapA {
		addEdge(1, 0, int(q)-1, start, int(q)-1, e, AddBoth)
	}
	for e, start := range mapB {
		addEdge(1, 0, int(q)-1, start, int(q)-1, e, AddAUB)
	}

	dsuA := NewDSU(n)
	dsuAUB := NewDSU(n)
	ans := make([]int32, q)

	var solve func(node, L, R int)
	solve = func(node, L, R int) {
		histA := len(dsuA.history)
		histAUB := len(dsuAUB.history)

		for idx := headA[node]; idx != -1; idx = pool[idx].next {
			dsuA.Merge(pool[idx].e.u, pool[idx].e.v)
		}
		for idx := headAUB[node]; idx != -1; idx = pool[idx].next {
			dsuAUB.Merge(pool[idx].e.u, pool[idx].e.v)
		}

		if L == R {
			ans[L] = dsuA.comps - dsuAUB.comps
		} else {
			mid := L + (R - L)/2
			solve(node*2, L, mid)
			solve(node*2+1, mid+1, R)
		}

		dsuA.Rollback(histA)
		dsuAUB.Rollback(histAUB)
	}

	solve(1, 0, int(q)-1)

	out := make([]byte, 0, q*10)
	for _, v := range ans {
		if v == 0 {
			out = append(out, '0')
		} else {
			var b [12]byte
			idx := 12
			for v > 0 {
				idx--
				b[idx] = byte(v%10 + '0')
				v /= 10
			}
			out = append(out, b[idx:]...)
		}
		out = append(out, '\n')
	}
	os.Stdout.Write(out)
}