//cf707d
/*
题意:维护一个图,支持四种操作
1.第i行第j列变为1
2.第i行第j列变为0
3.第i行颠倒,1变0,0变1
4.将整张图变为第k次操作时的状态,如果k是0的话,则清空图
*/

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+100;
const int M=maxn*6;
struct node {
int l,r,lazy,sum;
}segTree[M];
int T[maxn];
int tot,n,m,q;
void pushdown (int i,int l,int r) {
segTree[i].sum=segTree[segTree[i].l].sum+segTree[segTree[i].r].sum;
if (segTree[i].lazy) segTree[i].sum=r-l+1-segTree[i].sum;
}

void build (int &rt,int l,int r) {
rt=++tot;
if (l==r) return;
int mid=(l+r)>>1;
build(segTree[rt].l,l,mid);
build(segTree[rt].r,mid+1,r);
pushdown(rt,l,r);
}
void up (int &rt,int k,int l,int r,int x,int y) {
if (r<x||l>x) return;
rt=++tot;
segTree[rt]=segTree[k];
if (l==r) {
segTree[rt].sum=y;
return;
}
y^=segTree[k].lazy;
int mid=(l+r)>>1;
up(segTree[rt].l,segTree[k].l,l,mid,x,y);
up(segTree[rt].r,segTree[k].r,mid+1,r,x,y);
pushdown(rt,l,r);
}
void up2 (int &rt,int k,int l,int r,int x,int y) {
if (r<x||l>y) return;
rt=++tot;
segTree[rt]=segTree[k];
if (x<=l&&y>=r) {
segTree[rt].lazy^=1;
segTree[rt].sum=r-l+1-segTree[rt].sum;
return;
}
int mid=(l+r)>>1;
up2(segTree[rt].l,segTree[k].l,l,mid,x,y);
up2(segTree[rt].r,segTree[k].r,mid+1,r,x,y);
pushdown(rt,l,r);
}

int main () {
scanf("%d%d%d",&n,&m,&q);
build(T[0],1,n*m);
for (int i=1;i<=q;i++) {
int p,x;
scanf("%d%d",&p,&x);
if (p<=2) {
int y;
scanf("%d",&y);
up(T[i],T[i-1],1,n*m,(x-1)*m+y,p&1);
}
if (p==3) {
up2(T[i],T[i-1],1,n*m,(x-1)*m+1,x*m);
}
if (p==4)
T[i]=T[x];
printf("%d\n",segTree[T[i]].sum);
}
}