#include <bits/stdc++.h>
using namespace std;
struct Node {
  int cnt, L, R;
  bitset<1001> val;
  Node() {
    cnt = 0;
    bitset<1001> val = 0;
    L = R = -1;
  }
  Node(int x, int y, int z, bitset<1001> v) {
    L = x;
    R = y;
    cnt = z;
    val = v;
  }
} tree[2000 * 1001];
int root[100001];
int gc = 0;
bitset<1001> PPP = 0;
int build(int L, int R) {
  ++gc;
  if (L == R) return gc;
  int x = gc;
  tree[x] = Node(build(L, ((L + R) >> 1)), build(((L + R) >> 1) + 1, R), 0, 0);
  return x;
}
int add(int L, int R, int root, int idx, int pos) {
  if (L > idx || R < idx) return root;
  ++gc;
  if (L == idx && R == idx) {
    bitset<1001> temp = tree[root].val;
    temp.set(pos);
    tree[gc] = Node(-1, -1, temp.count(), temp);
    return gc;
  }
  int x = gc;
  int left = add(L, ((L + R) >> 1), tree[root].L, idx, pos);
  int right = add(((L + R) >> 1) + 1, R, tree[root].R, idx, pos);
  tree[x] = Node(left, right, tree[left].cnt + tree[right].cnt, 0);
  return x;
}
int remove(int L, int R, int root, int idx, int pos) {
  if (L > idx || R < idx) return root;
  ++gc;
  if (L == idx && R == idx) {
    bitset<1001> temp = tree[root].val;
    temp.reset(pos);
    tree[gc] = Node(-1, -1, temp.count(), temp);
    return gc;
  }
  int x = gc;
  int left = remove(L, ((L + R) >> 1), tree[root].L, idx, pos);
  int right = remove(((L + R) >> 1) + 1, R, tree[root].R, idx, pos);
  tree[x] = Node(left, right, tree[left].cnt + tree[right].cnt, 0);
  return x;
}
int invert(int L, int R, int root, int idx) {
  if (L > idx || R < idx) return root;
  ++gc;
  if (L == idx && R == idx) {
    bitset<1001> temp = tree[root].val;
    temp ^= PPP;
    tree[gc] = Node(-1, -1, temp.count(), temp);
    return gc;
  }
  int x = gc;
  int left = invert(L, ((L + R) >> 1), tree[root].L, idx);
  int right = invert(((L + R) >> 1) + 1, R, tree[root].R, idx);
  tree[x] = Node(left, right, tree[left].cnt + tree[right].cnt, 0);
  return x;
}
int query(int L, int R, int root, int idx, int pos) {
  if (idx < L || idx > R) return 0;
  if (L == R) return tree[root].val[pos] == 1;
  return query(L, ((L + R) >> 1), tree[root].L, idx, pos) +
         query(((L + R) >> 1) + 1, R, tree[root].R, idx, pos);
}
int main() {
  int n, m, q, x, y, ch;
  cin >> n >> m >> q;
  for (int i = 1; i < m + 1; i++) PPP.set(i);
  root[0] = build(1, n);
  for (int i = 1; i < q + 1; i++) {
    cin >> ch;
    if (ch == 1) {
      cin >> x >> y;
      int P = query(1, n, root[i - 1], x, y);
      if (!P)
        root[i] = add(1, n, root[i - 1], x, y);
      else
        root[i] = root[i - 1];
    } else if (ch == 2) {
      cin >> x >> y;
      int P = query(1, n, root[i - 1], x, y);
      if (P)
        root[i] = remove(1, n, root[i - 1], x, y);
      else
        root[i] = root[i - 1];
    } else if (ch == 3) {
      cin >> x;
      root[i] = invert(1, n, root[i - 1], x);
    } else {
      cin >> x;
      root[i] = root[x];
    }
    cout << tree[root[i]].cnt << endl;
  }
  return 0;
}
