```go
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
type BitSet struct {
words []uint64
cnt int
}
func (b *BitSet) Clone() *BitSet {
w := make([]uint64, len(b.words))
copy(w, b.words)
return &BitSet{words: w, cnt: b.cnt}
}
func (b *BitSet) Set(j int) bool {
idx := j >> 6
bit := uint(j & 63)
mask := uint64(1) << bit
if (b.words[idx] & mask) == 0 {
b.words[idx] |= mask
b.cnt++
return true
}
return false
}
func (b *BitSet) Clear(j int) bool {
idx := j >> 6
bit := uint(j & 63)
mask := uint64(1) << bit
if (b.words[idx] & mask) != 0 {
b.words[idx] &^= mask
b.cnt--
return true
}
return false
}
func (b *BitSet) Invert(mm int) {
for i := range b.words {
b.words[i] = ^b.words[i]
}
if mm&63 != 0 {
lastIdx := len(b.words) - 1
mask := (uint64(1) << (mm & 63)) - 1
b.words[lastIdx] &= mask
}
b.cnt = mm - b.cnt
}
type Node struct {
sum int
left *Node
right *Node
shelf *BitSet
}
func Update(node *Node, l, r, pos int, newShelf *BitSet) *Node {
if l == r {
return &Node{sum: newShelf.cnt, shelf: newShelf}
}
mid := (l + r) >> 1
var left, right *Node
if node != nil {
left, right = node.left, node.right
}
if pos <= mid {
left = Update(left, l, mid, pos, newShelf)
} else {
right = Update(right, mid+1, r, pos, newShelf)
}
sum := 0
if left != nil {
sum += left.sum
}
if right != nil {
sum += right.sum
}
return &Node{sum: sum, left: left, right: right}
}
func Query(node *Node, l, r, pos int) *BitSet {
if node == nil {
return nil
}
if l == r {
return node.shelf
}
mid := (l + r) >> 1
if pos <= mid {
return Query(node.left, l, mid, pos)
}
return Query(node.right, mid+1, r, pos)
}
func main() {
reader := bufio.NewReader(os.Stdin)
writer := bufio.NewWriter(os.Stdout)
defer writer.Flush()
line, _ := reader.ReadString('\n')
line = strings.TrimSpace(line)
parts := strings.Fields(line)
n, _ := strconv.Atoi(parts[0])
m, _ := strconv.Atoi(parts[1])
q, _ := strconv.Atoi(parts[2])
wordCount := (m + 63) / 64
emptyShelf := &BitSet{words: make([]uint64, wordCount), cnt: 0}
roots := make([]*Node, q+1)
totals := make([]int, q+1)
for op := 1; op <= q; op++ {
line, _ = reader.ReadString('\n')
line = strings.TrimSpace(line)
parts = strings.Fields(line)
typ, _ := strconv.Atoi(parts[0])
switch typ {
case 1:
i, _ := strconv.Atoi(parts[1])
j, _ := strconv.Atoi(parts[2])
j--
prevRoot := roots[op-1]
oldShelf := Query(prevRoot, 1, n, i)
if oldShelf == nil {
oldShelf = emptyShelf
}
newShelf := oldShelf.Clone()
if newShelf.Set(j) {
roots[op] = Update(prevRoot, 1, n, i, newShelf)
totals[op] = roots[op].sum
} else {
roots[op] = prevRoot
totals[op] = totals[op-1]
}
case 2:
i, _ := strconv.Atoi(parts[1])
j, _ := strconv.Atoi(parts[2])
j--
prevRoot := roots[op-1]
oldShelf := Query(prevRoot, 1, n, i)
if oldShelf == nil {
oldShelf = emptyShelf
}
newShelf := oldShelf.Clone()
if newShelf.Clear(j) {
roots[op] = Update(prevRoot, 1, n, i, newShelf)
totals[op] = roots[op].sum
} else {
roots[op] = prevRoot
totals[op] = totals[op-1]
}
case 3:
i, _ := strconv.Atoi(parts[1])
prevRoot := roots[op-1]
oldShelf := Query(prevRoot, 1, n, i)
if oldShelf == nil {
oldShelf = emptyShelf
}
newShelf := oldShelf.Clone()
newShelf.Invert(m)
roots[op] = Update(prevRoot, 1, n, i, newShelf)
totals[op] = roots[op].sum
case 4:
k, _ := strconv.Atoi(parts[1])
roots[op] = roots[k]
totals[op] = totals[k]
}
fmt.Fprintln(writer, totals[op])
}
}
```