← Home
package main

import (
	"bufio"
	"os"
	"strconv"
)

type Edge struct {
	u, v int32
}

type DSU struct {
	parent []int32
	sz     []int32
	comps  int
	hist   []int32
}

func NewDSU(n int) *DSU {
	parent := make([]int32, n+1)
	sz := make([]int32, n+1)
	for i := 1; i <= n; i++ {
		parent[i] = int32(i)
		sz[i] = 1
	}
	return &DSU{
		parent: parent,
		sz:     sz,
		comps:  n,
		hist:   make([]int32, 0, 1000000),
	}
}

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

func (d *DSU) Union(i, j int32) {
	rootI := d.Find(i)
	rootJ := d.Find(j)
	if rootI != rootJ {
		if d.sz[rootI] < d.sz[rootJ] {
			rootI, rootJ = rootJ, rootI
		}
		d.parent[rootJ] = rootI
		d.sz[rootI] += d.sz[rootJ]
		d.comps--
		d.hist = append(d.hist, rootJ)
	} else {
		d.hist = append(d.hist, 0)
	}
}

func (d *DSU) Undo() {
	last := len(d.hist) - 1
	rootJ := d.hist[last]
	d.hist = d.hist[:last]
	if rootJ != 0 {
		rootI := d.parent[rootJ]
		d.sz[rootI] -= d.sz[rootJ]
		d.parent[rootJ] = rootJ
		d.comps++
	}
}

var treeA [][]Edge
var treeAB [][]Edge

func addEdge(tree [][]Edge, node, l, r, ql, qr int, e Edge) {
	if l > qr || r < ql {
		return
	}
	if ql <= l && r <= qr {
		tree[node] = append(tree[node], e)
		return
	}
	mid := l + (r-l)/2
	addEdge(tree, 2*node, l, mid, ql, qr, e)
	addEdge(tree, 2*node+1, mid+1, r, ql, qr, e)
}

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	scanner.Split(bufio.ScanWords)
	scanner.Buffer(make([]byte, 1024*1024), 10*1024*1024)

	scanInt := func() int {
		scanner.Scan()
		res, _ := strconv.Atoi(scanner.Text())
		return res
	}

	scanString := func() string {
		scanner.Scan()
		return scanner.Text()
	}

	n := scanInt()
	q := scanInt()

	treeA = make([][]Edge, 4*q+1)
	treeAB = make([][]Edge, 4*q+1)

	inA := make(map[int64]bool)
	inB := make(map[int64]bool)
	lastA := make(map[int64]int)
	lastAB := make(map[int64]int)
	countAB := make(map[int64]int)

	for i := 1; i <= q; i++ {
		t := scanString()
		u := scanInt()
		v := scanInt()
		if u > v {
			u, v = v, u
		}
		key := int64(u)<<32 | int64(v)
		edge := Edge{int32(u), int32(v)}

		if t == "A" {
			if inA[key] {
				inA[key] = false
				addEdge(treeA, 1, 1, q, lastA[key], i-1, edge)
				countAB[key]--
				if countAB[key] == 0 {
					addEdge(treeAB, 1, 1, q, lastAB[key], i-1, edge)
				}
			} else {
				inA[key] = true
				lastA[key] = i
				countAB[key]++
				if countAB[key] == 1 {
					lastAB[key] = i
				}
			}
		} else {
			if inB[key] {
				inB[key] = false
				countAB[key]--
				if countAB[key] == 0 {
					addEdge(treeAB, 1, 1, q, lastAB[key], i-1, edge)
				}
			} else {
				inB[key] = true
				countAB[key]++
				if countAB[key] == 1 {
					lastAB[key] = i
				}
			}
		}
	}

	for key, in := range inA {
		if in {
			u, v := int32(key>>32), int32(key)
			addEdge(treeA, 1, 1, q, lastA[key], q, Edge{u, v})
		}
	}
	for key, count := range countAB {
		if count > 0 {
			u, v := int32(key>>32), int32(key)
			addEdge(treeAB, 1, 1, q, lastAB[key], q, Edge{u, v})
		}
	}

	ans := make([]int, q+1)
	dsuA := NewDSU(n)
	dsuAB := NewDSU(n)

	var dfs func(node, l, r int)
	dfs = func(node, l, r int) {
		for _, e := range treeA[node] {
			dsuA.Union(e.u, e.v)
		}
		for _, e := range treeAB[node] {
			dsuAB.Union(e.u, e.v)
		}

		if l == r {
			ans[l] = dsuA.comps - dsuAB.comps
		} else {
			mid := l + (r-l)/2
			dfs(2*node, l, mid)
			dfs(2*node+1, mid+1, r)
		}

		for i := 0; i < len(treeA[node]); i++ {
			dsuA.Undo()
		}
		for i := 0; i < len(treeAB[node]); i++ {
			dsuAB.Undo()
		}
	}

	if q > 0 {
		dfs(1, 1, q)
	}

	writer := bufio.NewWriter(os.Stdout)
	for i := 1; i <= q; i++ {
		writer.WriteString(strconv.Itoa(ans[i]) + "\n")
	}
	writer.Flush()
}