#pragma GCC optimize("O3")
#include <bits/stdc++.h>
using namespace std;
typedef  long long ll;
typedef  vector<int> vi;
typedef  pair<int,int> pii;
typedef  pair<ll,int> pli;
typedef  pair<int,string> pis;
double   pi=3.1415926535898;
#define speed      ios::sync_with_stdio(false);cin.tie(NULL); cout.tie(NULL);
#define lop(i,n)    for(int i=0;i<int(n);i++)
#define ff(i,a,b)  for(int i=a;i<=int(b);++i)
#define fr(i,a,b)  for(int i=a;i>=int(b);i--)
#define ms(x,a)    memset(x,a,sizeof(x))
#define all(x)     (x).begin(),(x).end()
#define sz(x)      int(x.size())
#define pb         push_back
#define r0         return 0;
#define CC         continue;
#define bb(x)      cerr<< x <<endl;
#define f          first
//#define s          second       //  __builtin_popcount;
//freopen("input.txt","r",stdin),freopen("output.txt","w",stdout);
string ys = "YES\n";
string no = "NO\n" ;
const double EPS = 1e-6;
const int inf = 1<<20;
const ll M  = 1e9+7 ;
const int N = 100100;
const int maxn = 105;
/////  for (int i= -inf ; i < inf ; i++)   Hi  :P

int a[N];
int b[N];
int n;

int f(int d){
    int cnt=0;
    for(int i=0 ; i<n ; i++)
        b[i]=a[i];

    for(int i=2 ; i<n ; i++){
        if(b[i]-b[i-1] == d) continue;
        if(b[i]-b[i-1]+1 == d){
            b[i]++;
            cnt++;
            continue;
        }
        if(b[i]-b[i-1]-1 == d){
            b[i]--;
            cnt++;
            continue;
        }

        return inf;
    }

    return cnt;
}

int main()
{

    scanf("%d",&n);
    for(int i=0 ; i<n ; i++)
        scanf("%d",&a[i]);

    if(n < 3){
        printf("0");
        return 0;
    }

    int ans=inf;
    int d=a[1]-a[0];

    ans=min(f(d),ans);
    ans=min(1+f(d+1),ans);
    ans=min(1+f(d-1),ans);

    a[1]++;
    ans=min(1+f(d+1),ans);
    ans=min(2+f(d+2),ans);
    ans=min(2+f(d),ans);

    a[1]-=2;
    ans=min(1+f(d-1),ans);
    ans=min(2+f(d-2),ans);
    ans=min(2+f(d),ans);

    if(ans == inf) printf("-1");
    else printf("%d",ans);

    return 0;
}

/*
int mx[]= {0,0,1,-1, 1,1,-1,-1};
int my[]= {1,-1,0,0, 1,-1,1,-1};
bool inside (int i,int j){return (i>=0 && i<n && j>=0 && j<m);}

ll BIT[100100];
void update(int x, int delta)
{
    for(; x <= N; x += x&-x)
        BIT[x] += delta;
}
ll query(int x)
{
    ll sum = 0;
    for(; x > 0; x -= x&-x)
        sum += BIT[x];
    return sum;
}

bool prime[1000005];
void sieve()
{
    for(int i=4; i<=1000000; i+=2)
        prime[i]=false,prime[i-1]=true;
    prime[2]=true;
    for(int i=3; i<=1000; i+=2)
    {
        if(prime[i])
        {
            for(int j=i*i; j<=1000000; j+=i*2)
                prime[j]=false;
        }
    }
}

for (int i=0; i<n; i++)            Hi    ^_^  hack me if you can :P
typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> pbds;

*/
/*
freopen("output.txt","w",stdout);
freopen("input.txt","r",stdin);

ll pwmod(ll a, ll n, ll mod)
{
ll ret = 1;
while (n)
{
if (n & 1) ret = ret * a % mod;
a = a * a % mod;
n >>= 1;
}
return ret;
}

void gcd(LL n,LL m,LL &d,LL &xx,LL &yy)
{
if(!m)
{
d=n;
xx=1;
yy=0;
}
else
{
gcd(m,n%m,d,yy,xx);
yy-=xx*(n/m);
}
}

int getm(int l,int r)
{
if(l>r)
return N;
if(l==r)
return 0;
if(l==r-1)
return s[l] != s[r];
if(s[l]==s[r])
return getm(l+1,r-1);
else
return 1+min(getm(l+1,r),getm(l,r-1));
}

int n, a[N];
int seg[N<<2];

void build(int nd,int L,int R)
{
if( L == R )
{
seg[nd]=a[L];
return ;
}
int mid = (L+R) >>1;
build(nd<<1,L, mid);
build(nd<<1|1,mid+1,R);
seg[nd]=max( seg[nd<<1], seg[nd<<1|1] );
}

void update(int nd,int L,int R,int idx,int val)
{
if( L == R )
{
seg[nd]=val;
return ;
}
int mid = (L+R) >>1;
if( idx<=mid )
update(nd<<1,  L,mid,idx,val);
else update(nd<<1|1,mid+1, R,idx,val);
seg[nd]=max( seg[nd<<1], seg[nd<<1|1] );
}

int query(int nd,int L,int R,int from,int to)
{
if( from<=L && R<=to )return seg[nd];
if( from>R || to<L )return -inf;

int mid = (L+R) >>1;

int ansl = query(nd<<1,  L,mid,from,to);
int ansr= query(nd<<1|1,mid+1, R,from,to);
return max( anrl,ansr );
}
*/


#pragma GCC optimize("O3")
#include <bits/stdc++.h>
using namespace std;
typedef  long long ll;
typedef  vector<int> vi;
typedef  pair<int,int> pii;
typedef  pair<ll,int> pli;
typedef  pair<int,string> pis;
double   pi=3.1415926535898;
#define speed      ios::sync_with_stdio(false);cin.tie(NULL); cout.tie(NULL);
#define lop(i,n)    for(int i=0;i<int(n);i++)
#define ff(i,a,b)  for(int i=a;i<=int(b);++i)
#define fr(i,a,b)  for(int i=a;i>=int(b);i--)
#define ms(x,a)    memset(x,a,sizeof(x))
#define all(x)     (x).begin(),(x).end()
#define sz(x)      int(x.size())
#define pb         push_back
#define r0         return 0;
#define CC         continue;
#define bb(x)      cerr<< x <<endl;
#define f          first
//#define s          second       //  __builtin_popcount;
//freopen("input.txt","r",stdin),freopen("output.txt","w",stdout);
string ys = "YES\n";
string no = "NO\n" ;
const double EPS = 1e-6;
const int inf = 1<<20;
const ll M  = 1e9+7 ;
const int N = 100100;
const int maxn = 105;
//////////////////////  Hi ^_^  hack me if you can :P

ll n,w;
ll ans,c, d;
ll a[100100];
ll b[100100];
int mx[]= {0,0,1,-1, 1,1,-1,-1};
int my[]= {1,-1,0,0, 1,-1,1,-1};

int main()
{
    speed;
    cin >> n;
    ff(i,1,n)
    {
        cin >> a[i];
    }

    if (n <= 2)
    {
        cout << 0 << endl;
        return 0;
    }

    ans = n+1;
    ff(k,0,7)
    {
        ff(i,1,n) b[i] = a[i];
        b[1] += mx[k];
        b[2] += my[k];
        d = b[2]-b[1];
        c = abs(mx[k])+abs(my[k]);
        ff(i,3,n)
        {
            if (b[i]-b[i-1] == d) continue;
            else if (b[i]-b[i-1] == d+1)
            {
                b[i]++;
                c++;
                continue;
            }
            else if (b[i]-b[i-1] == d-1)
            {
                b[i]--;
                c++;
                continue;
            }
            else c = n+1;
        }
        ans = min(ans,c);
    }
    if (ans == n+1)
    {
        ans = -1;
    }
    cout<< ans<<endl;
}

/*

ll BIT[100100];

void update(int x, int delta)
{
    for(; x <= N; x += x&-x)
        BIT[x] += delta;
}

ll query(int x)
{
    ll sum = 0;
    for(; x > 0; x -= x&-x)
        sum += BIT[x];
    return sum;
}

bool prime[1000005];
void sieve()
{
    for(int i=4; i<=1000000; i+=2)
        prime[i]=false,prime[i-1]=true;
    prime[2]=true;
    for(int i=3; i<=1000; i+=2)
    {
        if(prime[i])
        {
            for(int j=i*i; j<=1000000; j+=i*2)
                prime[j]=false;
        }
    }
}

for (int i=0; i<n; i++)            Hi    ^_^  hack me if you can :P
typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> pbds;

*/
/*
freopen("output.txt","w",stdout);
freopen("input.txt","r",stdin);

ll pwmod(ll a, ll n, ll mod)
{
ll ret = 1;
while (n)
{
if (n & 1) ret = ret * a % mod;
a = a * a % mod;
n >>= 1;
}
return ret;
}

int mx[]= {0,0,1,-1, 1,1,-1,-1};
int my[]= {1,-1,0,0, 1,-1,1,-1};

bool inside (int i,int j){return (i>=0 && i<n && j>=0 && j<m);}

void gcd(LL n,LL m,LL &d,LL &xx,LL &yy)
{
if(!m)
{
d=n;
xx=1;
yy=0;
}
else
{
gcd(m,n%m,d,yy,xx);
yy-=xx*(n/m);
}
}

int getm(int l,int r)
{
if(l>r)
return N;
if(l==r)
return 0;
if(l==r-1)
return s[l] != s[r];
if(s[l]==s[r])
return getm(l+1,r-1);
else
return 1+min(getm(l+1,r),getm(l,r-1));
}

int n, a[N];
int seg[N<<2];

void build(int nd,int L,int R)
{
if( L == R )
{
seg[nd]=a[L];
return ;
}
int mid = (L+R) >>1;
build(nd<<1,L, mid);
build(nd<<1|1,mid+1,R);
seg[nd]=max( seg[nd<<1], seg[nd<<1|1] );
}

void update(int nd,int L,int R,int idx,int val)
{
if( L == R )
{
seg[nd]=val;
return ;
}
int mid = (L+R) >>1;
if( idx<=mid )
update(nd<<1,  L,mid,idx,val);
else update(nd<<1|1,mid+1, R,idx,val);
seg[nd]=max( seg[nd<<1], seg[nd<<1|1] );
}

int query(int nd,int L,int R,int from,int to)
{
if( from<=L && R<=to )return seg[nd];
if( from>R || to<L )return -inf;

int mid = (L+R) >>1;

int ansl = query(nd<<1,  L,mid,from,to);
int ansr= query(nd<<1|1,mid+1, R,from,to);
return max( anrl,ansr );
}
*/


#pragma GCC optimize("O3")
#include <bits/stdc++.h>
using namespace std;
typedef  long long ll;
typedef  vector<int> vi;
typedef  pair<int,int> pii;
typedef  pair<ll,int> pli;
typedef  pair<int,string> pis;
double   pi=3.1415926535898;
#define speed      ios::sync_with_stdio(false);cin.tie(NULL); cout.tie(NULL);
#define lop(i,n)    for(int i=0;i<int(n);i++)
#define ff(i,a,b)  for(int i=a;i<=int(b);++i)
#define fr(i,a,b)  for(int i=a;i>=int(b);i--)
#define ms(x,a)    memset(x,a,sizeof(x))
#define all(x)     (x).begin(),(x).end()
#define sz(x)      int(x.size())
#define pb         push_back
#define r0         return 0;
#define CC         continue;
#define bb(x)      cerr<< x <<endl;
#define f          first
//#define s          second       //  __builtin_popcount;
//freopen("input.txt","r",stdin),freopen("output.txt","w",stdout);
string ys = "YES\n";
string no = "NO\n" ;
const double EPS = 1e-6;
const int inf = 1<<20;
const ll M  = 1e9+7 ;
const int N = 100100;
const int maxn = 105;
//////////////////////  Hi ^_^  hack me if you can :P

ll n,w;
ll ans,c, d;
ll a[100100];
ll b[100100];
//int mx[]= {0,0,1,-1, 1,1,-1,-1};
//int my[]= {1,-1,0,0, 1,-1,1,-1};

int mx[]= {0,0,0,1,1,1,-1,-1,-1};
int my[]= {0,1,-1,0,1,-1,0,1,-1};

int main()
{
    speed;
    cin >> n;
    ff(i,1,n)
    {
        cin >> a[i];
    }

    if (n <= 2LL)
    {
        cout << 0 << endl;
        return 0;
    }

    ans = n+1LL;
    ff(k,0,7)
    {
        ff(i,1,n) b[i] = a[i];

        b[1] += mx[k];
        b[2] += my[k];

        d = b[1]-b[2];

        c = abs(mx[k])+abs(my[k]);

        ff(i,3,n)
        {
            if (b[i-1] - b[i] != d)
            {
                if (b[i-1]-b[i] == d+1LL)
                {
                    b[i]++;
                    c++;
                }
                else if (b[i-1]-b[i] == d-1LL)
                {
                    b[i]--;
                    c++;
                }
                else
                {
                    c = n+1LL;
                    break;
                }
            }
        }
        ans = min(ans,c);
    }
    if (ans == n+1LL)
    {
        ans = -1LL;
    }
    cout<< ans<<endl;
}

/*

ll BIT[100100];

void update(int x, int delta)
{
    for(; x <= N; x += x&-x)
        BIT[x] += delta;
}

ll query(int x)
{
    ll sum = 0;
    for(; x > 0; x -= x&-x)
        sum += BIT[x];
    return sum;
}

bool prime[1000005];
void sieve()
{
    for(int i=4; i<=1000000; i+=2)
        prime[i]=false,prime[i-1]=true;
    prime[2]=true;
    for(int i=3; i<=1000; i+=2)
    {
        if(prime[i])
        {
            for(int j=i*i; j<=1000000; j+=i*2)
                prime[j]=false;
        }
    }
}

for (int i=0; i<n; i++)            Hi    ^_^  hack me if you can :P
typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> pbds;

*/
/*
freopen("output.txt","w",stdout);
freopen("input.txt","r",stdin);

ll pwmod(ll a, ll n, ll mod)
{
ll ret = 1;
while (n)
{
if (n & 1) ret = ret * a % mod;
a = a * a % mod;
n >>= 1;
}
return ret;
}

int mx[]= {0,0,1,-1, 1,1,-1,-1};
int my[]= {1,-1,0,0, 1,-1,1,-1};

bool inside (int i,int j){return (i>=0 && i<n && j>=0 && j<m);}

void gcd(LL n,LL m,LL &d,LL &xx,LL &yy)
{
if(!m)
{
d=n;
xx=1;
yy=0;
}
else
{
gcd(m,n%m,d,yy,xx);
yy-=xx*(n/m);
}
}

int getm(int l,int r)
{
if(l>r)
return N;
if(l==r)
return 0;
if(l==r-1)
return s[l] != s[r];
if(s[l]==s[r])
return getm(l+1,r-1);
else
return 1+min(getm(l+1,r),getm(l,r-1));
}

int n, a[N];
int seg[N<<2];

void build(int nd,int L,int R)
{
if( L == R )
{
seg[nd]=a[L];
return ;
}
int mid = (L+R) >>1;
build(nd<<1,L, mid);
build(nd<<1|1,mid+1,R);
seg[nd]=max( seg[nd<<1], seg[nd<<1|1] );
}

void update(int nd,int L,int R,int idx,int val)
{
if( L == R )
{
seg[nd]=val;
return ;
}
int mid = (L+R) >>1;
if( idx<=mid )
update(nd<<1,  L,mid,idx,val);
else update(nd<<1|1,mid+1, R,idx,val);
seg[nd]=max( seg[nd<<1], seg[nd<<1|1] );
}

int query(int nd,int L,int R,int from,int to)
{
if( from<=L && R<=to )return seg[nd];
if( from>R || to<L )return -inf;

int mid = (L+R) >>1;

int ansl = query(nd<<1,  L,mid,from,to);
int ansr= query(nd<<1|1,mid+1, R,from,to);
return max( anrl,ansr );
}
*/


#include <bits/stdc++.h>
using namespace std;
#define N 1010

int n, m, q, type, a, b, f[N], ans[N*N];
bool vis[N][N], r[N];

void add(int i, int j) {
	if (!r[i]) {
		if (vis[i][j]) return;
		vis[i][j] = 1;
		f[i] ++;
	}
	else {
		if (!vis[i][j]) return;
		vis[i][j] = 0;
		f[i] ++;
	}
}

void del(int i, int j) {
	if (!r[i]) {
		if (!vis[i][j]) return;
		vis[i][j] = 0;
		f[i] --;
	}
	else {
		if (vis[i][j]) return;
		vis[i][j] = 1;
		f[i] --;
	}
}

void Reverse(int i) {
	r[i] = 1 - r[i];
	f[i] = m - f[i];
}

int calc() {
	int rlt = 0;
	for (int i = 1; i <= n; i ++) rlt += f[i];
	return rlt;
}

int main() {
//	freopen("d.in", "r", stdin);
	scanf("%d %d %d", &n, &m, &q);
	for (int i = 1; i <= q; i ++) {
		scanf("%d", &type);
		if (type == 1) {
			scanf("%d %d", &a, &b);
			add(a, b);
		}
		else if (type == 2) {
			scanf("%d %d", &a, &b);
			del(a, b);
		}
		else if (type == 3) {
			scanf("%d", &a);
			Reverse(a);
		}
		else {
			scanf("%d", &a);
			printf("%d\n", ans[a]);
		}
		if (type != 4) {
			ans[i] = calc();
			printf("%d\n", ans[i]);
		}
	}
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define M 20000100

int cur, n, m, Q;

struct Node {
  Node *l, *r;
  int sz[2]; bool rev;
} pool[M], *nil = pool + (cur++);

Node* root[1000010];

void init() {
  nil -> l = nil, nil -> r = nil;
  nil -> sz[0] = 1; nil -> sz[1] = 0;
  nil -> rev = 0;
}

void up(Node* now) {
  for (int i = 0; i < 2; i++)
    now -> sz[i] = now -> l -> sz[i] + now -> r -> sz[i];
}

void down(Node* now, int l = 0, int r = 0) {
  if (now -> rev) {
    swap(now -> l -> sz[0], now -> l -> sz[1]);
    swap(now -> r -> sz[0], now -> r -> sz[1]);
    now -> l -> rev = now -> r -> rev = 1;
    now -> rev = 0;
  }
}

void copy(Node* now, Node* old) {
  now -> l = old -> l, now -> r = old -> r;
  now -> rev = old -> rev;
  for (int i = 0; i < 2; i++) now -> sz[i] = old -> sz[i];
}

Node* build(int l, int r) {
  Node* now = pool + (cur++);
  if (l == r) {copy(now, nil); return now;}
  int mid = (l + r) >> 1;
  now -> l = build(l, mid);
  now -> r = build(mid + 1, r);
  up(now);
  return now;
}

Node* update(Node *old, int l, int r, int x, int bf) {
  Node* now = pool + (cur++); copy(now, old);
  if (l == r) {
    if (bf) now -> sz[0] = 0, now -> sz[1] = 1;
    else now -> sz[0] = 1, now -> sz[1] = 0;
    return now;
  }
  down(now, l, r);
  int mid = (l + r) >> 1;
  if (x <= mid) now -> l = update(old -> l, l, mid, x, bf);
  else now -> r = update(old -> r, mid + 1, r, x, bf);

  //printf("%d %d\n", now -> l -> sz[1], now -> r -> sz[1]);

  up(now);
  return now;
}

Node* invert(Node *old, int st, int en, int l, int r) {
  Node* now = pool + (cur++); copy(now, old);
  if (l <= st && en <= r) {
    swap(now -> sz[0], now -> sz[1]);
    (now -> rev) ^= 1;
    return now;
  }
  down(now);
  int mid = (st + en) >> 1;
  if (l <= mid) now -> l = invert(old -> l, st, mid, l, r);
  if (mid < r) now -> r = invert(old -> r, mid + 1, en, l, r);
  up(now);
  return now;
}

int main() {
  //freopen("in.txt", "r", stdin);
  init();
  scanf("%d %d %d", &n, &m, &Q);
  root[0] = build(1, n * m);
  printf("%d %d\n",root[0] -> l -> sz[0], root[0] -> r -> sz[1]);
  for (int i = 1; i <= Q; i++) {
    int type, x, y;
    scanf("%d", &type);
    if (type == 1) {
      scanf("%d %d", &x, &y);
      root[i] = update(root[i - 1], 1, m * n, (x - 1) * m + y, 1);
    }
    else if (type == 2) {
      scanf("%d %d", &x, &y);
      root[i] = update(root[i - 1], 1, m * n, (x - 1) * m + y, 0);
    }
    else if (type == 3) {
      scanf("%d", &x);
      root[i] = invert(root[i - 1], 1, m * n, (x - 1) * m + 1, x * m);
    }
    else {
      scanf("%d", &x);
      root[i] = pool + (cur++);
      copy(root[i], root[x]);
    }
    printf("%d\n", root[i] -> sz[1]);
  }
}


#include <bits/stdc++.h>
using namespace std;
#define M 25000100

int cur, n, m, Q;

struct Node {
  Node *l, *r;
  int sz[2]; bool rev;
} pool[M], *nil = pool + (cur++);

Node* root[1000010];

void init() {
  nil -> l = nil, nil -> r = nil;
  nil -> sz[0] = 1; nil -> sz[1] = 0;
  nil -> rev = 0;
}

void up(Node* now) {
  for (int i = 0; i < 2; i++)
    now -> sz[i] = now -> l -> sz[i] + now -> r -> sz[i];
}

void down(Node* now, int l = 0, int r = 0) {
  if (now -> rev) {
    //Node *L = pool + (cur++);
    //copy(L, now -> l);
    //swap(L -> sz[0], L -> sz[1]);
    swap(now -> l -> sz[0], now -> l -> sz[1]);
    swap(now -> r -> sz[0], now -> r -> sz[1]);
    now -> l -> rev = now -> r -> rev = 1;
    now -> rev = 0;
  }
}

void copy(Node* now, Node* old) {
  now -> l = old -> l, now -> r = old -> r;
  now -> rev = old -> rev;
  for (int i = 0; i < 2; i++) now -> sz[i] = old -> sz[i];
}

Node* build(int l, int r) {
  Node* now = pool + (cur++);
  if (l == r) {copy(now, nil); return now;}
  int mid = (l + r) >> 1;
  now -> l = build(l, mid);
  now -> r = build(mid + 1, r);
  up(now);
  return now;
}

Node* update(Node *old, int l, int r, int x, int bf) {
  Node* now = pool + (cur++); copy(now, old);
  if (l == r) {
    if (bf) now -> sz[0] = 0, now -> sz[1] = 1;
    else now -> sz[0] = 1, now -> sz[1] = 0;
    return now;
  }
  down(now, l, r);
  int mid = (l + r) >> 1;
  if (x <= mid) now -> l = update(old -> l, l, mid, x, bf);
  else now -> r = update(old -> r, mid + 1, r, x, bf);

  //printf("%d %d\n", now -> l -> sz[1], now -> r -> sz[1]);

  up(now);
  return now;
}

Node* invert(Node *old, int st, int en, int l, int r) {
  Node* now = pool + (cur++); copy(now, old);
  if (l <= st && en <= r) {
    swap(now -> sz[0], now -> sz[1]);
    (now -> rev) ^= 1;
    return now;
  }
  down(now);
  int mid = (st + en) >> 1;
  if (l <= mid) now -> l = invert(old -> l, st, mid, l, r);
  if (mid < r) now -> r = invert(old -> r, mid + 1, en, l, r);
  up(now);
  return now;
}

int main() {
  //freopen("in.txt", "r", stdin);
  init();
  scanf("%d %d %d", &n, &m, &Q);
  root[0] = build(1, n * m);
  for (int i = 1; i <= Q; i++) {
    int type, x, y;
    scanf("%d", &type);
    root[i] = pool + (cur++);
    if (type == 1) {
      scanf("%d %d", &x, &y);
      root[i] = update(root[i - 1], 1, m * n, (x - 1) * m + y, 1);
    }
    else if (type == 2) {
      scanf("%d %d", &x, &y);
      root[i] = update(root[i - 1], 1, m * n, (x - 1) * m + y, 0);
    }
    else if (type == 3) {
      scanf("%d", &x);
      root[i] = invert(root[i - 1], 1, m * n, (x - 1) * m + 1, x * m);
    }
    else {
      scanf("%d", &x);
      copy(root[i], root[x]);
    }
    printf("%d\n", root[i] -> sz[1]);
  }
}


#include <bits/stdc++.h>
using namespace std;
#define M 1010
#define N 100100

int n, m, q, a[N], b[N], c[N];
vector <int> v[N];
bool vis[M][M];
int type[N], r[M], d[M], f[N];

void dfs(int x) {
	for (int i = 0; i < v[x].size(); i ++) {
		int y = v[x][i];
		if (type[y] == 1) {
			int now = vis[a[y]][b[y]];
			if (now ^ r[a[y]]) f[y] = f[x];
			else f[y] = f[x] + 1, d[a[y]] ++;
			vis[a[y]][b[y]] = r[a[y]] ^ 1;
			dfs(y);
			vis[a[y]][b[y]] = now;
			if (!(now ^ r[a[y]])) d[a[y]] --;
		}
		else if (type[y] == 2) {
			int now = vis[a[y]][b[y]];
			if (now ^ r[a[y]]) f[y] = f[x] - 1, d[a[y]] --;
			else f[y] = f[x];
			vis[a[y]][b[y]] = r[a[y]];
			dfs(y);
			vis[a[y]][b[y]] = now;
			if (now ^ r[a[y]]) d[a[y]] ++;
		}
		else if (type[y] == 3) {
			f[y] = f[x] - d[c[y]] + m - d[c[y]];
			r[c[y]] ^= 1;
			d[c[y]] = m - d[c[y]];
			dfs(y);
			r[c[y]] ^= 1;
			d[c[y]] = m - d[c[y]];
		}
		else {
			f[y] = f[x];
			dfs(y);
		}
	}
}

int main() {
//	freopen("d.in", "r", stdin);
	scanf("%d %d %d", &n, &m, &q);
	for (int i = 1; i <= q; i ++) {
		scanf("%d", &type[i]);
		if (type[i] <= 2) {
			scanf("%d %d", &a[i], &b[i]);
		}
		else if (type[i] == 3) {
			scanf("%d", &c[i]);
		}
		else {
			int x = 0;
			scanf("%d", &x);
			v[x].push_back(i);
		}
		if (type[i] <= 3) v[i-1].push_back(i);
	}
	dfs(0);
	for (int i = 1; i <= q; i ++) printf("%d\n", f[i]);
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define M 2000100

int cur, n, m, Q;

struct Node {
  Node *l, *r;
  int sz[2]; bool rev;
} pool[M], *nil = pool + (cur++);

Node* root[1000010];

void init() {
  nil -> l = nil, nil -> r = nil;
  nil -> sz[0] = 1; nil -> sz[1] = 0;
  nil -> rev = 0;
}

void up(Node* now) {
  for (int i = 0; i < 2; i++)
    now -> sz[i] = now -> l -> sz[i] + now -> r -> sz[i];
}

void down(Node* now, int l = 0, int r = 0) {
  if (now -> rev) {
    swap(now -> l -> sz[0], now -> l -> sz[1]);
    swap(now -> r -> sz[0], now -> r -> sz[1]);
    now -> l -> rev = now -> r -> rev = 1;
    now -> rev = 0;
  }
}

void copy(Node* now, Node* old) {
  now -> l = old -> l, now -> r = old -> r;
  now -> rev = old -> rev;
  for (int i = 0; i < 2; i++) now -> sz[i] = old -> sz[i];
}

Node* build(int l, int r) {
  Node* now = pool + (cur++);
  if (l == r) {copy(now, nil); return now;}
  int mid = (l + r) >> 1;
  now -> l = build(l, mid);
  now -> r = build(mid + 1, r);
  up(now);
  return now;
}

Node* update(Node *old, int l, int r, int x, int bf) {
  Node* now = pool + (cur++); copy(now, old);
  if (l == r) {
    if (bf) now -> sz[0] = 0, now -> sz[1] = 1;
    else now -> sz[0] = 1, now -> sz[1] = 0;
    return now;
  }
  down(now, l, r);
  int mid = (l + r) >> 1;
  if (x <= mid) now -> l = update(old -> l, l, mid, x, bf);
  else now -> r = update(old -> r, mid + 1, r, x, bf);

  //printf("%d %d\n", now -> l -> sz[1], now -> r -> sz[1]);

  up(now);
  return now;
}

Node* invert(Node *old, int st, int en, int l, int r) {
  Node* now = pool + (cur++); copy(now, old);
  if (l <= st && en <= r) {
    swap(now -> sz[0], now -> sz[1]);
    (now -> rev) ^= 1;
    return now;
  }
  down(now);
  int mid = (st + en) >> 1;
  if (l <= mid) now -> l = invert(old -> l, st, mid, l, r);
  if (mid < r) now -> r = invert(old -> r, mid + 1, en, l, r);
  up(now);
  return now;
}

int main() {
  //freopen("in.txt", "r", stdin);
  init();
  scanf("%d %d %d", &n, &m, &Q);
  root[0] = build(1, n * m);
  for (int i = 1; i <= Q; i++) {
    int type, x, y;
    scanf("%d", &type);
    if (type == 1) {
      scanf("%d %d", &x, &y);
      root[i] = update(root[i - 1], 1, m * n, (x - 1) * m + y, 1);
    }
    else if (type == 2) {
      scanf("%d %d", &x, &y);
      root[i] = update(root[i - 1], 1, m * n, (x - 1) * m + y, 0);
    }
    else if (type == 3) {
      scanf("%d", &x);
      root[i] = invert(root[i - 1], 1, m * n, (x - 1) * m + 1, x * m);
    }
    else {
      scanf("%d", &x);
      root[i] = pool + (cur++);
      copy(root[i], root[x]);
    }
    printf("%d\n", root[i] -> sz[1]);
  }
}


#include <bits/stdc++.h>
using namespace std;
#define M 25000100

int cur, n, m, Q;

struct Node {
  Node *l, *r;
  int sz[2]; bool rev;
} pool[M], *nil = pool + (cur++);

Node* root[1000010];

void init() {
  nil -> l = nil, nil -> r = nil;
  nil -> sz[0] = 1; nil -> sz[1] = 0;
  nil -> rev = 0;
}

void up(Node* now) {
  for (int i = 0; i < 2; i++)
    now -> sz[i] = now -> l -> sz[i] + now -> r -> sz[i];
}

void down(Node* now, int l = 0, int r = 0) {
  if (now -> rev) {
    swap(now -> l -> sz[0], now -> l -> sz[1]);
    swap(now -> r -> sz[0], now -> r -> sz[1]);
    now -> l -> rev = now -> r -> rev = 1;
    now -> rev = 0;
  }
}

void copy(Node* now, Node* old) {
  now -> l = old -> l, now -> r = old -> r;
  now -> rev = old -> rev;
  for (int i = 0; i < 2; i++) now -> sz[i] = old -> sz[i];
}

Node* build(int l, int r) {
  Node* now = pool + (cur++);
  if (l == r) {copy(now, nil); return now;}
  int mid = (l + r) >> 1;
  now -> l = build(l, mid);
  now -> r = build(mid + 1, r);
  up(now);
  return now;
}

Node* update(Node *old, int l, int r, int x, int bf) {
  Node* now = pool + (cur++); copy(now, old);
  if (l == r) {
    if (bf) now -> sz[0] = 0, now -> sz[1] = 1;
    else now -> sz[0] = 1, now -> sz[1] = 0;
    return now;
  }
  down(now, l, r);
  int mid = (l + r) >> 1;
  if (x <= mid) now -> l = update(old -> l, l, mid, x, bf);
  else now -> r = update(old -> r, mid + 1, r, x, bf);

  //printf("%d %d\n", now -> l -> sz[1], now -> r -> sz[1]);

  up(now);
  return now;
}

Node* invert(Node *old, int st, int en, int l, int r) {
  Node* now = pool + (cur++); copy(now, old);
  if (l <= st && en <= r) {
    swap(now -> sz[0], now -> sz[1]);
    (now -> rev) ^= 1;
    return now;
  }
  down(now);
  int mid = (st + en) >> 1;
  if (l <= mid) now -> l = invert(old -> l, st, mid, l, r);
  if (mid < r) now -> r = invert(old -> r, mid + 1, en, l, r);
  up(now);
  return now;
}

int main() {
  //freopen("in.txt", "r", stdin);
  init();
  scanf("%d %d %d", &n, &m, &Q);
  root[0] = build(1, n * m);
  for (int i = 1; i <= Q; i++) {
    int type, x, y;
    scanf("%d", &type);
    if (type == 1) {
      scanf("%d %d", &x, &y);
      root[i] = update(root[i - 1], 1, m * n, (x - 1) * m + y, 1);
    }
    else if (type == 2) {
      scanf("%d %d", &x, &y);
      root[i] = update(root[i - 1], 1, m * n, (x - 1) * m + y, 0);
    }
    else if (type == 3) {
      scanf("%d", &x);
      root[i] = invert(root[i - 1], 1, m * n, (x - 1) * m + 1, x * m);
    }
    else {
      scanf("%d", &x);
      root[i] = pool + (cur++);
      copy(root[i], root[x]);
    }
    printf("%d\n", root[i] -> sz[1]);
  }
}


#include <bits/stdc++.h>
using namespace std;
#define M 20000100

int cur, n, m, Q;

struct Node {
  Node *l, *r;
  int sz[2]; bool rev;
} pool[M], *nil = pool + (cur++);

Node* root[1000010];

void init() {
  nil -> l = nil, nil -> r = nil;
  nil -> sz[0] = 1; nil -> sz[1] = 0;
  nil -> rev = 0;
}

void up(Node* now) {
  for (int i = 0; i < 2; i++)
    now -> sz[i] = now -> l -> sz[i] + now -> r -> sz[i];
}

void down(Node* now, int l = 0, int r = 0) {
  if (now -> rev) {
    swap(now -> l -> sz[0], now -> l -> sz[1]);
    swap(now -> r -> sz[0], now -> r -> sz[1]);
    now -> l -> rev = now -> r -> rev = 1;
    now -> rev = 0;
  }
}

void copy(Node* now, Node* old) {
  now -> l = old -> l, now -> r = old -> r;
  now -> rev = old -> rev;
  for (int i = 0; i < 2; i++) now -> sz[i] = old -> sz[i];
}

Node* build(int l, int r) {
  Node* now = pool + (cur++);
  if (l == r) {copy(now, nil); return now;}
  int mid = (l + r) >> 1;
  now -> l = build(l, mid);
  now -> r = build(mid + 1, r);
  up(now);
  return now;
}

Node* update(Node *old, int l, int r, int x, int bf) {
  Node* now = pool + (cur++); copy(now, old);
  if (l == r) {
    if (bf) now -> sz[0] = 0, now -> sz[1] = 1;
    else now -> sz[0] = 1, now -> sz[1] = 0;
    return now;
  }
  down(now, l, r);
  int mid = (l + r) >> 1;
  if (x <= mid) now -> l = update(old -> l, l, mid, x, bf);
  else now -> r = update(old -> r, mid + 1, r, x, bf);

  //printf("%d %d\n", now -> l -> sz[1], now -> r -> sz[1]);

  up(now);
  return now;
}

Node* invert(Node *old, int st, int en, int l, int r) {
  Node* now = pool + (cur++); copy(now, old);
  if (l <= st && en <= r) {
    swap(now -> sz[0], now -> sz[1]);
    (now -> rev) ^= 1;
    return now;
  }
  down(now);
  int mid = (st + en) >> 1;
  if (l <= mid) now -> l = invert(old -> l, st, mid, l, r);
  if (mid < r) now -> r = invert(old -> r, mid + 1, en, l, r);
  up(now);
  return now;
}

int main() {
  //freopen("in.txt", "r", stdin);
  init();
  scanf("%d %d %d", &n, &m, &Q);
  root[0] = build(1, n * m);

  for (int i = 1; i <= Q; i++) {
    int type, x, y;
    scanf("%d", &type);
    //root[i] = pool + (cur++);
    if (type == 1) {
      scanf("%d %d", &x, &y);
      root[i] = update(root[i - 1], 1, m * n, (x - 1) * m + y, 1);
    }
    else if (type == 2) {
      scanf("%d %d", &x, &y);
      root[i] = update(root[i - 1], 1, m * n, (x - 1) * m + y, 0);
    }
    else if (type == 3) {
      scanf("%d", &x);
      root[i] = invert(root[i - 1], 1, m * n, (x - 1) * m + 1, x * m);
    }
    else {
      scanf("%d", &x);
      root[i] = root[x];
    }
    printf("%d\n", root[i] -> sz[1]);
  }
}


#include <bits/stdc++.h>
using namespace std;
#define M 1011
typedef pair<int, int> pii;
int T;
struct ST{
	vector<pii> state;
	int chk;
    void add_state(int time, int val){
    	state.push_back(pii(time, val));
    }
    void roll_back(int time){
    	if(chk == T) return;
    	chk = T;

    	if(state.empty() || state.rbegin()->first <= time) return;
    	int val;
    	if(state[0].first > time) val = 0;
    	else{
			int lo = 0, hi = state.size() - 1;
			while(hi - lo > 1){
				int m = (lo + hi) / 2;
				if(state[m].first <= time) lo = m;
				else hi = m;
			}
			val = state[lo].second;
    	}

        state.push_back(pii(state.rbegin()->first, val));
    }
    int current(){
    	if(state.empty()) return 0;
    	return state.rbegin()->second;
    }
};
ST b[M];
ST c[M][M];
int Q[100011];
ST d[M];

int main() {
	int n, m, q;
	scanf("%d %d %d", &n, &m, &q);

	int all = 0, t = 0, current_time = q;
	while(q--){
		++t;
		int op, x, y;
        scanf("%d", &op);
        if(op == 1 || op == 2){
        	scanf("%d %d", &x, &y);
        	b[x].roll_back(current_time);
            c[x][y].roll_back(current_time);
            d[x].roll_back(current_time);
			if(b[x].current() ^ c[x][y].current() ^ (op & 1)){
				all += 3 - op * 2;
				c[x][y].add_state(t, c[x][y].current()^1);

				d[x].add_state(t, d[x].current() + 3 - op * 2);

			}
        }else if(op == 3){
        	scanf("%d", &x);

        	b[x].roll_back(current_time);
            d[x].roll_back(current_time);
            //printf("%d %d\n", b[x].current(), d[x].current());
            b[x].add_state(t, b[x].current() ^ 1);

            all += m - 2 * d[x].current();
            d[x].add_state(t, d[x].current() + m - 2 * d[x].current());
        }else{
        	scanf("%d", &x);
			all = Q[x];
			current_time = x;
			++T;
        }
        Q[t] = all;
        printf("%d\n", all);
	}

}


#include <bits/stdc++.h>
using namespace std;
#define M 1011
typedef pair<int, int> pii;
int T;
struct ST{
	vector<pii> state;
	int chk;
    void add_state(int time, int val){
    	state.push_back(pii(time, val));
    }
    void roll_back(int time){
    	if(chk == T) return;
    	chk = T;
    	int val;
    	if(state[0].first > time) val = 0;
    	else{
			int lo = 0, hi = state.size() - 1;
			while(hi - lo > 1){
				int m = (lo + hi) / 2;
				if(state[m].first <= time) lo = m;
				else hi = m;
			}
			val = state[lo].second;
    	}

        state.push_back(pii(state.rbegin()->first, val));
    }
    int current(){
    	if(state.empty()) return 0;
    	return state.rbegin()->second;
    }
};
ST b[M];
map<pii, ST*> c;
int Q[100001];
ST d[M];

int main() {
	int n, m, q;
	scanf("%d %d %d", &n, &m, &q);

	int all = 0, t = 0, current_time = q;
	while(q--){
		++t;
		int op, x, y;
        scanf("%d", &op);
        if(op == 1 || op == 2){
        	scanf("%d %d", &x, &y);
        	b[x].roll_back(current_time);
            if(c.find(pii(x, y)) == c.end()) c[pii(x, y)] = new ST();
            c[pii(x, y)]->roll_back(current_time);
            d[x].roll_back(current_time);
			if(b[x].current() ^ c[pii(x, y)]->current() ^ (op & 1)){
				all += 3 - op * 2;
				c[pii(x, y)]->add_state(t, c[pii(x, y)]->current()^1);

				d[x].add_state(t, d[x].current() + 3 - op * 2);

			}
        }else if(op == 3){
        	scanf("%d", &x);

        	b[x].roll_back(current_time);
            d[x].roll_back(current_time);
            //printf("%d %d\n", b[x].current(), d[x].current());
            b[x].add_state(t, b[x].current() ^ 1);

            all += m - 2 * d[x].current();
            d[x].add_state(t, d[x].current() + m - 2 * d[x].current());
        }else{
        	scanf("%d", &x);
			all = Q[x];
			current_time = x;
			++T;
        }
        Q[t] = all;
        printf("%d\n", all);
	}

}


#include <bits/stdc++.h>
using namespace std;
#define N 1010
#define M 100100

int n, m, q, type, a, b;
int last[M][N], f[M];
bool on[M][N];

int main() {
	scanf("%d %d %d", &n, &m, &q);
	for (int t = 1; t <= q; t ++) {
		for (int i = 1; i <= n; i ++) last[t][i] = last[t-1][i];
		scanf("%d", &type);
		if (type == 1 || type == 2) {
			scanf("%d %d", &a, &b);
			f[t] = f[t-1];
            for (int j = 1; j <= m; j ++) on[t][j] = on[last[t][a]][j];
			last[t][a] = t;
			f[t] -= on[t][b];
			on[t][b] = (type == 1);
			f[t] += on[t][b];
		}
		else if (type == 3) {
			scanf("%d", &a);
			f[t] = f[t-1];
			for (int j = 1; j <= m; j ++) {
				f[t] -= on[last[t][a]][j];
				on[t][j] = !on[last[t][a]][j];
				f[t] += on[t][j];
			}
			last[t][a] = t;
		}
		else {
			scanf("%d", &a);
			f[t] = f[a];
			for (int i = 1; i <= n; i ++) last[t][i] = last[a][i];
		}
		printf("%d\n", f[t]);
	}
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define M 25000100

int cur, n, m, Q;

struct Node {
  Node *l, *r;
  int sz[2]; bool rev;
} pool[M], *nil = pool + (cur++);

Node* root[1000010];

void init() {
  nil -> l = nil, nil -> r = nil;
  nil -> sz[0] = 1; nil -> sz[1] = 0;
  nil -> rev = 0;
}

void up(Node* now) {
  for (int i = 0; i < 2; i++)
    now -> sz[i] = now -> l -> sz[i] + now -> r -> sz[i];
}

void down(Node* now, int l = 0, int r = 0) {
  if (now -> rev) {
    //Node *L = pool + (cur++);
    //copy(L, now -> l);
    //swap(L -> sz[0], L -> sz[1]);
    swap(now -> l -> sz[0], now -> l -> sz[1]);
    swap(now -> r -> sz[0], now -> r -> sz[1]);
    now -> l -> rev = now -> r -> rev = 1;
    now -> rev = 0;
  }
}

void copy(Node* now, Node* old) {
  now -> l = old -> l, now -> r = old -> r;
  now -> rev = old -> rev;
  for (int i = 0; i < 2; i++) now -> sz[i] = old -> sz[i];
}

Node* build(int l, int r) {
  Node* now = pool + (cur++);
  if (l == r) {copy(now, nil); return now;}
  int mid = (l + r) >> 1;
  now -> l = build(l, mid);
  now -> r = build(mid + 1, r);
  up(now);
  return now;
}

Node* update(Node *old, int l, int r, int x, int bf) {
  Node* now = pool + (cur++); copy(now, old);
  if (l == r) {
    if (bf) now -> sz[0] = 0, now -> sz[1] = 1;
    else now -> sz[0] = 1, now -> sz[1] = 0;
    return now;
  }
  down(now, l, r);
  int mid = (l + r) >> 1;
  if (x <= mid) copy(now -> l, update(old -> l, l, mid, x, bf));
  else copy(now -> r, update(old -> r, mid + 1, r, x, bf));

  //printf("%d %d\n", now -> l -> sz[1], now -> r -> sz[1]);

  up(now);
  return now;
}

Node* invert(Node *old, int st, int en, int l, int r) {
  Node* now = pool + (cur++); copy(now, old);
  if (l <= st && en <= r) {
    swap(now -> sz[0], now -> sz[1]);
    (now -> rev) ^= 1;
    return now;
  }
  down(now);
  int mid = (st + en) >> 1;
  if (l <= mid) copy(now -> l, invert(old -> l, st, mid, l, r));
  if (mid < r) copy(now -> r, invert(old -> r, mid + 1, en, l, r));
  up(now);
  return now;
}

int main() {
  //freopen("in.txt", "r", stdin);
  init();
  scanf("%d %d %d", &n, &m, &Q);
  root[0] = build(1, n * m);
  for (int i = 1; i <= Q; i++) {
    int type, x, y;
    scanf("%d", &type);
    root[i] = pool + (cur++);
    if (type == 1) {
      scanf("%d %d", &x, &y);
      copy(root[i], update(root[i - 1], 1, m * n, (x - 1) * m + y, 1));
    }
    else if (type == 2) {
      scanf("%d %d", &x, &y);
      copy(root[i], update(root[i - 1], 1, m * n, (x - 1) * m + y, 0));
    }
    else if (type == 3) {
      scanf("%d", &x);
      copy(root[i], invert(root[i - 1], 1, m * n, (x - 1) * m + 1, x * m));
    }
    else {
      scanf("%d", &x);
      copy(root[i], root[x]);
    }
    printf("%d\n", root[i] -> sz[1]);
  }
}


#include <bits/stdc++.h>
using namespace std;
#define M 2500100

int cur, n, m, Q;

struct Node {
  Node *l, *r;
  int sz[2]; bool rev;
} pool[M], *nil = pool + (cur++);

Node* root[1000010];

void init() {
  nil -> l = nil, nil -> r = nil;
  nil -> sz[0] = 1; nil -> sz[1] = 0;
  nil -> rev = 0;
}

void up(Node* now) {
  for (int i = 0; i < 2; i++)
    now -> sz[i] = now -> l -> sz[i] + now -> r -> sz[i];
}

void down(Node* now, int l = 0, int r = 0) {
  if (now -> rev) {
    swap(now -> l -> sz[0], now -> l -> sz[1]);
    swap(now -> r -> sz[0], now -> r -> sz[1]);
    now -> l -> rev = now -> r -> rev = 1;
    now -> rev = 0;
  }
}

void copy(Node* now, Node* old) {
  now -> l = old -> l, now -> r = old -> r;
  now -> rev = old -> rev;
  for (int i = 0; i < 2; i++) now -> sz[i] = old -> sz[i];
}

Node* build(int l, int r) {
  Node* now = pool + (cur++);
  if (l == r) {copy(now, nil); return now;}
  int mid = (l + r) >> 1;
  now -> l = build(l, mid);
  now -> r = build(mid + 1, r);
  up(now);
  return now;
}

Node* update(Node *old, int l, int r, int x, int bf) {
  Node* now = pool + (cur++); copy(now, old);
  if (l == r) {
    if (bf) now -> sz[0] = 0, now -> sz[1] = 1;
    else now -> sz[0] = 1, now -> sz[1] = 0;
    return now;
  }
  down(now, l, r);
  int mid = (l + r) >> 1;
  if (x <= mid) now -> l = update(old -> l, l, mid, x, bf);
  else now -> r = update(old -> r, mid + 1, r, x, bf);

  //printf("%d %d\n", now -> l -> sz[1], now -> r -> sz[1]);

  up(now);
  return now;
}

Node* invert(Node *old, int st, int en, int l, int r) {
  Node* now = pool + (cur++); copy(now, old);
  if (l <= st && en <= r) {
    swap(now -> sz[0], now -> sz[1]);
    (now -> rev) ^= 1;
    return now;
  }
  down(now);
  int mid = (st + en) >> 1;
  if (l <= mid) now -> l = invert(old -> l, st, mid, l, r);
  if (mid < r) now -> r = invert(old -> r, mid + 1, en, l, r);
  up(now);
  return now;
}

int main() {
  //freopen("in.txt", "r", stdin);
  init();
  scanf("%d %d %d", &n, &m, &Q);
  root[0] = build(1, n * m);

  for (int i = 1; i <= Q; i++) {
    int type, x, y;
    scanf("%d", &type);
    //root[i] = pool + (cur++);
    if (type == 1) {
      scanf("%d %d", &x, &y);
      root[i] = update(root[i - 1], 1, m * n, (x - 1) * m + y, 1);
    }
    else if (type == 2) {
      scanf("%d %d", &x, &y);
      root[i] = update(root[i - 1], 1, m * n, (x - 1) * m + y, 0);
    }
    else if (type == 3) {
      scanf("%d", &x);
      root[i] = invert(root[i - 1], 1, m * n, (x - 1) * m + 1, x * m);
    }
    else {
      scanf("%d", &x);
      copy(root[i], root[x]);
    }
    printf("%d\n", root[i] -> sz[1]);
  }
}


#include <bits/stdc++.h>
using namespace std;
#define N 1010

int n, m, q, type, a, b, f[N], ans[N*N];
bool vis[N][N], r[N];

void add(int i, int j) {
	if (!r[i]) {
		if (vis[i][j]) return;
		vis[i][j] = 1;
		f[i] ++;
	}
	else {
		if (!vis[i][j]) return;
		vis[i][j] = 0;
		f[i] ++;
	}
}

void del(int i, int j) {
	if (!r[i]) {
		if (!vis[i][j]) return;
		vis[i][j] = 0;
		f[i] --;
	}
	else {
		if (vis[i][j]) return;
		vis[i][j] = 1;
		f[i] --;
	}
}

void inv(int i) {
	r[i] = 1 - r[i];
	f[i] = m - f[i];
}

int calc() {
	int rlt = 0;
	for (int i = 1; i <= n; i ++) rlt += f[i];
	return rlt;
}

int main() {
//	freopen("d.in", "r", stdin);
	scanf("%d %d %d", &n, &m, &q);
	for (int i = 1; i <= q; i ++) {
		scanf("%d", &type);
		if (type == 1) {
			scanf("%d %d", &a, &b);
			add(a, b);
		}
		else if (type == 2) {
			scanf("%d %d", &a, &b);
			del(a, b);
		}
		else if (type == 3) {
			scanf("%d", &a);
			inv(a);
		}
		else {
			scanf("%d", &a);
			printf("%d\n", ans[a]);
		}
		if (type != 4) {
			ans[i] = calc();
			printf("%d\n", ans[i]);
		}
		else ans[i] = ans[i-1];
	}
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define N 1010
#define M 100100

int n, m, q, type, a, b;
int last[M][N], f[M];
bool on[M][N];

int main() {
//	freopen("d.in", "r", stdin);
	scanf("%d %d %d", &n, &m, &q);
	for (int t = 1; t <= q; t ++) {
		for (int i = 1; i <= n; i ++) last[t][i] = last[t-1][i];
		scanf("%d", &type);
		if (type == 1 || type == 2) {
			scanf("%d %d", &a, &b);
			f[t] = f[t-1];
			f[t] -= on[last[t][a]][b];
			last[t][a] = t;
			on[t][b] = (type == 1);
			f[t] += on[t][b];
		}
		else if (type == 3) {
			scanf("%d", &a);
			f[t] = f[t-1];
			for (int j = 1; j <= m; j ++) {
				f[t] -= on[last[t][a]][j];
				on[t][j] = !on[last[t][a]][j];
				f[t] += on[t][j];
			}
			last[t][a] = t;
		}
		else {
			scanf("%d", &a);
			f[t] = f[a];
			for (int i = 1; i <= n; i ++) last[t][i] = last[a][i];
		}
	}
	for (int i = 1; i <= q; i ++) printf("%d\n", f[i]);
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define M 25000100

int cur, n, m, Q;

struct Node {
  Node *l, *r;
  int sz[2]; bool rev;
} pool[M], *nil = pool + (cur++);

Node* root[1000010];

void init() {
  nil -> l = nil, nil -> r = nil;
  nil -> sz[0] = 1; nil -> sz[1] = 0;
  nil -> rev = 0;
}

void up(Node* now) {
  for (int i = 0; i < 2; i++)
    now -> sz[i] = now -> l -> sz[i] + now -> r -> sz[i];
}

void down(Node* now, int l = 0, int r = 0) {
  if (now -> rev) {
    //Node *L = pool + (cur++);
    //copy(L, now -> l);
    //swap(L -> sz[0], L -> sz[1]);
    swap(now -> l -> sz[0], now -> l -> sz[1]);
    swap(now -> r -> sz[0], now -> r -> sz[1]);
    now -> l -> rev = now -> r -> rev = 1;
    now -> rev = 0;
  }
}

void copy(Node* now, Node* old) {
  now -> l = old -> l, now -> r = old -> r;
  now -> rev = old -> rev;
  for (int i = 0; i < 2; i++) now -> sz[i] = old -> sz[i];
}

Node* build(int l, int r) {
  Node* now = pool + (cur++);
  if (l == r) {copy(now, nil); return now;}
  int mid = (l + r) >> 1;
  now -> l = build(l, mid);
  now -> r = build(mid + 1, r);
  up(now);
  return now;
}

Node* update(Node *old, int l, int r, int x, int bf) {
  Node* now = pool + (cur++); copy(now, old);
  if (l == r) {
    if (bf) now -> sz[0] = 0, now -> sz[1] = 1;
    else now -> sz[0] = 1, now -> sz[1] = 0;
    return now;
  }
  down(now, l, r);
  int mid = (l + r) >> 1;
  if (x <= mid) copy(now -> l, update(old -> l, l, mid, x, bf));
  else copy(now -> r, update(old -> r, mid + 1, r, x, bf));

  //printf("%d %d\n", now -> l -> sz[1], now -> r -> sz[1]);

  up(now);
  return now;
}

Node* invert(Node *old, int st, int en, int l, int r) {
  Node* now = pool + (cur++); copy(now, old);
  if (l <= st && en <= r) {
    swap(now -> sz[0], now -> sz[1]);
    (now -> rev) ^= 1;
    return now;
  }
  down(now);
  int mid = (st + en) >> 1;
  if (l <= mid) copy(now -> l, invert(old -> l, st, mid, l, r));
  if (mid < r) copy(now -> r, invert(old -> r, mid + 1, en, l, r));
  up(now);
  return now;
}

int main() {
  //freopen("in.txt", "r", stdin);
  init();
  scanf("%d %d %d", &n, &m, &Q);
  root[0] = build(1, n * m);
  for (int i = 1; i <= Q; i++) {
    int type, x, y;
    scanf("%d", &type);
    root[i] = pool + (cur++);
    if (type == 1) {
      scanf("%d %d", &x, &y);
      root[i] = update(root[i - 1], 1, m * n, (x - 1) * m + y, 1);
    }
    else if (type == 2) {
      scanf("%d %d", &x, &y);
      root[i] = update(root[i - 1], 1, m * n, (x - 1) * m + y, 0);
    }
    else if (type == 3) {
      scanf("%d", &x);
      root[i] = invert(root[i - 1], 1, m * n, (x - 1) * m + 1, x * m);
    }
    else {
      scanf("%d", &x);
      copy(root[i], root[x]);
    }
    printf("%d\n", root[i] -> sz[1]);
  }
}


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define L long long
int n ,  m , q ;
const int maxn = 300050 ;
const int maxx = 1000050;
int root[maxn] ;
struct node {
    int l , r , sum ;
    int mark ;
}T[maxn * 40];
int cnt ;
void build(int l , int r ) {
    T[++cnt].sum = 0 ;
    T[cnt].l = T[cnt].r = 0;
    int x = cnt ;
    T[cnt].mark = 0 ;
    if(l == r) return ;
    int mid = (l + r) / 2 ;
    T[x].l = cnt + 1;
    build(l,mid) ;
    T[x].r = cnt + 1;
    build(mid+1,r) ;
}
int id(int x,int y){
    return (x-1)*m + y ;
}
void down(int ro,int l,int r) {
    if(l == r)return ;
    if(T[ro].mark == 0) return ;
    T[ro].mark = 0;
    int lson = T[ro].l ;
    int rson = T[ro].r ;
    int mid = (l + r) / 2;
    int llen = mid - l + 1;
    int rlen = r - mid ;
    T[lson].mark ^= 1 ;
    T[lson].sum = llen - T[lson].sum ;
    T[rson].mark ^= 1 ;
    T[rson].sum = rlen - T[rson].sum ;
    return ;
}
int query(int l,int r,int ro,int ll,int rr){
    if(l >= ll && r <= rr )return T[ro].sum ;
    down(ro,l,r) ;
    int mid = (l + r) / 2 ;
    if(rr <= mid) {
        return query(l,mid,T[ro].l,ll,rr);
    }
    else if(ll >= mid+1) {
        return query(mid+1,r,T[ro].r,ll,rr) ;
    }
    else return query(l,mid,T[ro].l,ll,rr) + query(mid+1,r,T[ro].r,ll,rr) ;
}
void crea(int l , int r , int &x , int y ) {
    down(y,l,r);
    T[++cnt] = T[y] ;
    x = cnt ;
    return ;
}
void upda1(int l,int r,int &x ,int y ,int pos , int val) {
    down(y , l , r) ;
    T[++cnt] = T[y] ;
    x = cnt ;
    T[cnt].sum += val ;
    if(l == r)return ;
    int mid = (l + r) / 2 ;
    if(pos <= mid) {
        upda1(l,mid,T[x].l , T[y].l , pos , val ) ;
    }
    else {
        upda1(mid+1,r,T[x].r , T[y].r , pos , val ) ;
    }
    up(x) ;
}
void up(int ro) {
    if(T[ro].l == 0) return ;
    int lson = T[ro].l , rson = T[ro].r ;
    T[ro].sum = T[lson].sum + T[rson].sum ;
}
void upda2(int l , int r , int &x , int y , int ql , int qr) {
    down(x , l , r) ;
    T[++cnt] = T[y] ;
    x = cnt ;
    if(l >= ql && r <= qr) {
        T[x].sum = r - l + 1 - T[x].sum ;
        T[x].mark = 1 ;
        return ;
    }
    if(l == r) return ;
    int mid = (l + r) / 2 ;
    if(ql <= mid ){
        upda2(l,mid,T[x].l , T[y].l , ql, qr) ;
    }
    if(qr >= mid + 1) {
        upda2(mid+1,r,T[x].r , T[y].r , ql , qr) ;
    }
    up(x) ;
}
int main(){
    scanf("%d%d%d",&n,&m,&q) ;
    cnt = 0 ;
    build(1,maxx) ;
    root[0] = 1;
    for(int i = 1 ; i<= q; i ++ ){
        int op;
        scanf("%d",&op);
        if(op == 1) {
            int x,y;
            scanf("%d%d",&x,&y);
            int sum = query(1,maxx , root[i-1] , id(x,y),id(x,y)) ;
            crea(1,maxx,root[i],root[i-1]) ;
            if(sum == 0) {
                upda1(1,maxx,root[i],root[i],id(x,y),1) ;
            }
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else if(op == 2) {
            int x,y;
            scanf("%d%d",&x,&y);
            int sum = query(1,maxx , root[i-1] , id(x,y),id(x,y)) ;
            crea(1,maxx,root[i],root[i-1]) ;
            if(sum == 1) {
                upda1(1,maxx,root[i],root[i],id(x,y),-1) ;
            }
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else if(op == 3) {
            int x;
            scanf("%d",&x);
            crea(1,maxx,root[i],root[i-1]) ;
            upda2(1,maxx , root[i] , root[i] , id(x,1) , id(x,m)) ;
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else {
            int k;
            scanf("%d",&k) ;
            crea(1,maxx,root[i],root[k]) ;
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
    }
}


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<queue>
#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<stack>
using namespace std;
int ans;
int a[1005][1005];
int c[1005][1005];
struct node
{
    int z;
    int i,j;
};
node b[100050];
int n,m;
int qu;
int main()
{
    memset(a,0,sizeof(a));
    scanf("%d%d%d",&n,&m,&qu);
    queue<int >q;
    for(int i=1; i<=qu; i++)
    {
        scanf("%d",&b[i].z);
        if(b[i].z==1||b[i].z==2)
        {
            scanf("%d%d",&b[i].i,&b[i].j);
        }
        else
        {
            if(b[i].z==3)
            {
                scanf("%d",&b[i].i);
            }
            else
            {
                scanf("%d",&b[i].i);
                q.push(b[i].i);
            }
        }
    }
    ans = 0;
    int w= 1;
    for(int i=1; i<=qu; i++)
    {
        if(b[i].z==1)
        {
            if(a[b[i].i][b[i].j]==0)
            {
                a[b[i].i][b[i].j]=1;
                ans ++;
            }
        }
        else if(b[i].z==2)
        {
            if(a[b[i].i][b[i].j]==1)
            {
                a[b[i].i][b[i].j]=0;
                ans --;
            }
        }
        else if(b[i].z==3)
        {
            for(int k=1; k<=m; k++)
            {
                if(a[b[i].i][k]==1)
                {
                    a[b[i].i][k]=0;
                    ans --;
                }
                else if(a[b[i].i][k]==0)
                {
                    a[b[i].i][k]=1;
                    ans ++;
                }
            }
        }
        else
        {
            if(b[i].i==0)
            {
                memset(a,0,sizeof(a));
                ans = 0;
            }
            else
            {
                q.pop();
                ans = 0;
                for(int k=1; k<=n; k++)
                {
                    for(int j=1; j<=m; j++)
                    {
                        a[k][j]=c[k][j];
                        if(a[k][j]==1)
                        {
                            ans++;
                        }
                    }
                }
            }
        }
        if(!q.empty()&&w==q.front())
        {
            for(int k=1; k<=n; k++)
            {
                for(int j=1; j<=m; j++)
                {
                    c[k][j]=a[k][j];
                }
            }
        }
        w++;
        printf("%d\n",ans);
    }
}

/**
19 16 14
3 10
3 8
3 3
2 5 3
1 7 15
4 0
2 11 2
1 16 3
1 16 3
3 13
1 13 3
4 9
1 5 11
3 1
*/


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define L long long
int n ,  m , q ;
const int maxn = 300050 ;
const int maxx = 1000050;
int root[maxn] ;
struct node {
    int l , r , sum ;
    int mark ;
}T[maxn * 40];
int cnt ;
void build(int l , int r ) {
    T[++cnt].sum = 0 ;
    T[cnt].l = T[cnt].r = 0;
    int x = cnt ;
    T[cnt].mark = 0 ;
    if(l == r) return ;
    int mid = (l + r) / 2 ;
    T[x].l = cnt + 1;
    build(l,mid) ;
    T[x].r = cnt + 1;
    build(mid+1,r) ;
}
int id(int x,int y){
    return (x-1)*m + y ;
}
void down(int ro,int l,int r) {
    if(l == r)return ;
    if(T[ro].mark == 0) return ;
    T[ro].mark = 0;
    int lson = T[ro].l ;
    int rson = T[ro].r ;
    int mid = (l + r) / 2;
    int llen = mid - l + 1;
    int rlen = r - mid ;
    T[lson].mark ^= 1 ;
    T[lson].sum = llen - T[lson].sum ;
    T[rson].mark ^= 1 ;
    T[rson].sum = rlen - T[rson].sum ;
    return ;
}
int query(int l,int r,int ro,int ll,int rr){
    if(l >= ll && r <= rr )return T[ro].sum ;
    if(l == r) return 0 ;
    down(ro,l,r) ;
    int mid = (l + r) / 2 ;
    if(rr <= mid) {
        return query(l,mid,T[ro].l,ll,rr);
    }
    else if(ll >= mid+1) {
        return query(mid+1,r,T[ro].r,ll,rr) ;
    }
    else return query(l,mid,T[ro].l,ll,rr) + query(mid+1,r,T[ro].r,ll,rr) ;
}
void crea(int l , int r , int &x , int y ) {
    down(y,l,r);
    T[++cnt] = T[y] ;
    x = cnt ;
    return ;
}
void up(int ro) {
    if(T[ro].l == 0) return ;
    int lson = T[ro].l , rson = T[ro].r ;
    T[ro].sum = T[lson].sum + T[rson].sum ;
}
void upda1(int l,int r,int &x ,int y ,int pos , int val) {
    down(y , l , r) ;
    T[++cnt] = T[y] ;
    x = cnt ;
    T[cnt].sum += val ;
    if(l == r)return ;
    int mid = (l + r) / 2 ;
    if(pos <= mid) {
        upda1(l,mid,T[x].l , T[y].l , pos , val ) ;
    }
    else {
        upda1(mid+1,r,T[x].r , T[y].r , pos , val ) ;
    }
    up(x) ;
}
void upda2(int l , int r , int &x , int y , int ql , int qr) {
    down(y , l , r) ;
    T[++cnt] = T[y] ;
    x = cnt ;
    if(l >= ql && r <= qr) {
        T[x].sum = r - l + 1 - T[x].sum ;
        T[x].mark = 1 ;
        return ;
    }
    if(l == r) return ;
    int mid = (l + r) / 2 ;
    if(ql <= mid ){
        upda2(l,mid,T[x].l , T[y].l , ql, qr) ;
    }
    if(qr >= mid + 1) {
        upda2(mid+1,r,T[x].r , T[y].r , ql , qr) ;
    }
    up(x) ;
}
int main(){
    scanf("%d%d%d",&n,&m,&q) ;
    cnt = 0 ;
    build(1,maxx) ;
    root[0] = 1;
    for(int i = 1 ; i<= q; i ++ ){
        int op;
        scanf("%d",&op);
        if(op == 1) {
            int x,y;
            scanf("%d%d",&x,&y);
            int sum = query(1,maxx , root[i-1] , id(x,y),id(x,y)) ;
            crea(1,maxx,root[i],root[i-1]) ;
            if(sum == 0) {
                upda1(1,maxx,root[i],root[i],id(x,y),1) ;
            }
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else if(op == 2) {
            int x,y;
            scanf("%d%d",&x,&y);
            int sum = query(1,maxx , root[i-1] , id(x,y),id(x,y)) ;
            crea(1,maxx,root[i],root[i-1]) ;
            if(sum == 1) {
                upda1(1,maxx,root[i],root[i],id(x,y),-1) ;
            }
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else if(op == 3) {
            int x;
            scanf("%d",&x);
            crea(1,maxx,root[i],root[i-1]) ;
            upda2(1,maxx , root[i] , root[i] , id(x,1) , id(x,m)) ;
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else {
            int k;
            scanf("%d",&k) ;
            crea(1,maxx,root[i],root[k]) ;
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
    }
}


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define L long long
int n ,  m , q ;
const int maxn = 300050 ;
const int maxx = 1000050;
int root[maxn] ;
struct node {
    int l , r , sum ;
    int mark ;
}T[maxn * 40];
int cnt ;
void build(int l , int r ) {
    T[++cnt].sum = 0 ;
    T[cnt].l = T[cnt].r = 0;
    int x = cnt ;
    T[cnt].mark = 0 ;
    if(l == r) return ;
    int mid = (l + r) / 2 ;
    T[x].l = cnt + 1;
    build(l,mid) ;
    T[x].r = cnt + 1;
    build(mid+1,r) ;
}
int id(int x,int y){
    return (x-1)*m + y ;
}
void down(int ro,int l,int r) {
    if(l == r)return ;
    if(T[ro].mark == 0) return ;
    T[ro].mark = 0;
    int lson = T[ro].l ;
    int rson = T[ro].r ;
    int mid = (l + r) / 2;
    int llen = mid - l + 1;
    int rlen = r - mid ;
    T[lson].mark ^= 1 ;
    T[lson].sum = llen - T[lson].sum ;
    T[rson].mark ^= 1 ;
    T[rson].sum = rlen - T[rson].sum ;
    return ;
}
int query(int l,int r,int ro,int ll,int rr){
    down(ro,l,r) ;
    if(l >= ll && r <= rr )return T[ro].sum ;
    int mid = (l + r) / 2 ;
    if(rr <= mid) {
        return query(l,mid,T[ro].l,ll,rr);
    }
    else if(ll >= mid+1) {
        return query(mid+1,r,T[ro].r,ll,rr) ;
    }
    else return query(l,mid,T[ro].l,ll,rr) + query(mid+1,r,T[ro].r,ll,rr) ;
}
void crea(int l , int r , int &x , int y ) {
    T[++cnt] = T[y] ;
    x = cnt ;
    return ;
}
void upda1(int l,int r,int &x ,int y ,int pos , int val) {
    down(y , l , r) ;
    T[++cnt] = T[y] ;
    x = cnt ;
    T[cnt].sum += val ;
    if(l == r)return ;
    int mid = (l + r) / 2 ;
    if(pos <= mid) {
        upda1(l,mid,T[x].l , T[y].l , pos , val ) ;
    }
    else {
        upda1(mid+1,r,T[x].r , T[y].r , pos , val ) ;
    }
}
void up(int ro) {
    if(T[ro].l == 0) return ;
    int lson = T[ro].l , rson = T[ro].r ;
    T[ro].sum = T[lson].sum + T[rson].sum ;
}
void upda2(int l , int r , int &x , int y , int ql , int qr) {
    down(x , l , r) ;
    T[++cnt] = T[y] ;
    x = cnt ;
    if(l >= ql && r <= qr) {
        T[x].sum = r - l + 1 - T[x].sum ;
        T[x].mark = 1 ;
        return ;
    }
    if(l == r) return ;
    int mid = (l + r) / 2 ;
    if(ql <= mid ){
        upda2(l,mid,T[x].l , T[y].l , ql, qr) ;
    }
    if(qr >= mid + 1) {
        upda2(mid+1,r,T[x].r , T[y].r , ql , qr) ;
    }
    up(x) ;
}
int main(){
    scanf("%d%d%d",&n,&m,&q) ;
    cnt = 0 ;
    build(1,maxx) ;
    root[0] = 1;
    for(int i = 1 ; i<= q; i ++ ){
        int op;
        scanf("%d",&op);
        if(op == 1) {
            int x,y;
            scanf("%d%d",&x,&y);
            int sum = query(1,maxx , root[i-1] , id(x,y),id(x,y)) ;
            crea(1,maxx,root[i],root[i-1]) ;
            if(sum == 0) {
                upda1(1,maxx,root[i],root[i],id(x,y),1) ;
            }
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else if(op == 2) {
            int x,y;
            scanf("%d%d",&x,&y);
            int sum = query(1,maxx , root[i-1] , id(x,y),id(x,y)) ;
            crea(1,maxx,root[i],root[i-1]) ;
            if(sum == 1) {
                upda1(1,maxx,root[i],root[i],id(x,y),-1) ;
            }
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else if(op == 3) {
            int x;
            scanf("%d",&x);
            crea(1,maxx,root[i],root[i-1]) ;
            upda2(1,maxx , root[i] , root[i] , id(x,1) , id(x,m)) ;
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else {
            int k;
            scanf("%d",&k) ;
            crea(1,maxx,root[i],root[k]) ;
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
    }
}


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<queue>
#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<stack>
using namespace std;
int ans;
int a[1005][1005];
int c[1005][1005];
struct node
{
    int z;
    int i,j;
};
node b[100050];
int n,m;
int qu;
int main()
{
    memset(a,0,sizeof(a));
    scanf("%d%d%d",&n,&m,&qu);
    queue<int >q;
    for(int i=1; i<=qu; i++)
    {
        scanf("%d",&b[i].z);
        if(b[i].z==1||b[i].z==2)
        {
            scanf("%d%d",&b[i].i,&b[i].j);
        }
        else
        {
            if(b[i].z==3)
            {
                scanf("%d",&b[i].i);
            }
            else
            {
                scanf("%d",&b[i].i);
                q.push(b[i].i);
            }
        }
    }
    ans = 0;
    int w= 1;
    for(int i=1; i<=qu; i++)
    {
        if(b[i].z==1)
        {
            if(a[b[i].i][b[i].j]==0)
            {
                a[b[i].i][b[i].j]=1;
                ans ++;
            }
        }
        else if(b[i].z==2)
        {
            if(a[b[i].i][b[i].j]==1)
            {
                a[b[i].i][b[i].j]=0;
                ans --;
            }
        }
        else if(b[i].z==3)
        {
            for(int k=1; k<=m; k++)
            {
                if(a[b[i].i][k]==1)
                {
                    a[b[i].i][k]=0;
                    ans --;
                }
                else if(a[b[i].i][k]==0)
                {
                    a[b[i].i][k]=1;
                    ans ++;
                }
            }
        }
        else
        {
            if(b[i].i==0)
            {
                memset(a,0,sizeof(a));
                ans = 0;
            }
            else
            {
                q.pop();
                ans = 0;
                for(int k=1; k<=n; k++)
                {
                    for(int j=1; j<=m; j++)
                    {
                        a[k][j]=c[k][j];
                        if(a[k][j]==1)
                        {
                            ans++;
                        }
                    }
                }
                w = b[i].i-1;
            }
        }
        if(!q.empty()&&w==q.front())
        {
            for(int k=1; k<=n; k++)
            {
                for(int j=1; j<=m; j++)
                {
                    c[k][j]=a[k][j];
                }
            }
        }
        w++;
        printf("%d\n",ans);
    }
}


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define L long long
int n ,  m , q ;
const int maxn = 100050 ;
const int maxx = 1000050;
int root[maxn] ;
struct node {
    int l , r , sum ;
    int mark ;
}T[maxn * 40];
int cnt ;
void build(int l , int r ) {
    T[++cnt].sum = 0 ;
    T[cnt].l = T[cnt].r = 0;
    int x = cnt ;
    T[cnt].mark = 0 ;
    if(l == r) return ;
    int mid = (l + r) / 2 ;
    T[x].l = cnt + 1;
    build(l,mid) ;
    T[x].r = cnt + 1;
    build(mid+1,r) ;
}
int id(int x,int y){
    return (x-1)*m + y ;
}
void down(int ro,int l,int r) {
    if(l == r)return ;
    if(T[ro].mark == 0) return ;
    T[ro].mark = 0;
    int lson = T[ro].l ;
    int rson = T[ro].r ;
    int mid = (l + r) / 2;
    int llen = mid - l + 1;
    int rlen = r - mid ;
    T[lson].mark ^= 1 ;
    T[lson].sum = llen - T[lson].sum ;
    T[rson].mark ^= 1 ;
    T[rson].sum = rlen - T[rson].sum ;
    return ;
}
int query(int l,int r,int ro,int ll,int rr){
    down(ro,l,r) ;
    if(l >= ll && r <= rr )return T[ro].sum ;
    int mid = (l + r) / 2 ;
    if(rr <= mid) {
        return query(l,mid,T[ro].l,ll,rr);
    }
    else if(ll >= mid+1) {
        return query(mid+1,r,T[ro].r,ll,rr) ;
    }
    else return query(l,mid,T[ro].l,ll,rr) + query(mid+1,r,T[ro].r,ll,rr) ;
}
void crea(int l , int r , int &x , int y ) {
    T[++cnt] = T[y] ;
    x = cnt ;
    return ;
}
void upda1(int l,int r,int &x ,int y ,int pos , int val) {
    T[++cnt] = T[y] ;
    x = cnt ;
    down(x , l , r) ;
    T[cnt].sum += val ;
    if(l == r)return ;
    int mid = (l + r) / 2 ;
    if(pos <= mid) {
        upda1(l,mid,T[x].l , T[y].l , pos , val ) ;
    }
    else {
        upda1(mid+1,r,T[x].r , T[y].r , pos , val ) ;
    }
}
void up(int ro) {
    if(T[ro].l == 0) return ;
    int lson = T[ro].l , rson = T[ro].r ;
    T[ro].sum = T[lson].sum + T[rson].sum ;
}
void upda2(int l , int r , int &x , int y , int ql , int qr) {
    T[++cnt] = T[y] ;
    x = cnt ;
    down(x , l , r) ;
    if(l >= ql && r <= qr) {
        T[x].sum = r - l + 1 - T[x].sum ;
        T[x].mark = 1 ;
        return ;
    }
    if(l == r) return ;
    int mid = (l + r) / 2 ;
    if(ql <= mid ){
        upda2(l,mid,T[x].l , T[y].l , ql, qr) ;
    }
    if(qr >= mid + 1) {
        upda2(mid+1,r,T[x].r , T[y].r , ql , qr) ;
    }
    up(x) ;
}
int main(){
    scanf("%d%d%d",&n,&m,&q) ;
    cnt = 0 ;
    build(1,maxx) ;
    root[0] = 1;
    for(int i = 1 ; i<= q; i ++ ){
        int op;
        scanf("%d",&op);
        if(op == 1) {
            int x,y;
            scanf("%d%d",&x,&y);
            int sum = query(1,maxx , root[i-1] , id(x,y),id(x,y)) ;
            crea(1,maxx,root[i],root[i-1]) ;
            if(sum == 0) {
                upda1(1,maxx,root[i],root[i],id(x,y),1) ;
            }
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else if(op == 2) {
            int x,y;
            scanf("%d%d",&x,&y);
            int sum = query(1,maxx , root[i-1] , id(x,y),id(x,y)) ;
            crea(1,maxx,root[i],root[i-1]) ;
            if(sum == 1) {
                upda1(1,maxx,root[i],root[i],id(x,y),-1) ;
            }
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else if(op == 3) {
            int x;
            scanf("%d",&x);
            crea(1,maxx,root[i],root[i-1]) ;
            upda2(1,maxx , root[i] , root[i] , id(x,1) , id(x,m)) ;
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else {
            int k;
            scanf("%d",&k) ;
            crea(1,maxx,root[i],root[k]) ;
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
    }
}


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define L long long
int n ,  m , q ;
const int maxn = 300050 ;
int maxx ;
int root[maxn] ;
struct node {
    int l , r , sum ;
   // int mark ;
}T[maxn * 40];
int cnt ;
void build(int l , int r ) {
    T[++cnt].sum = 0 ;
    T[cnt].l = T[cnt].r = 0;
    int x = cnt ;
  //  T[cnt].mark = 0 ;
    if(l == r) return ;
    int mid = (l + r) / 2 ;
    T[x].l = cnt + 1;
    build(l,mid) ;
    T[x].r = cnt + 1;
    build(mid+1,r) ;
}
int id(int x,int y){
    return (x-1)*m + y ;
}
/*
void down(int ro,int l,int r) {
    if(l == r)return ;
    if(T[ro].mark == 0) return ;
    T[ro].mark = 0;
    int lson = T[ro].l ;
    int rson = T[ro].r ;
    int mid = (l + r) / 2;
    int llen = mid - l + 1;
    int rlen = r - mid ;
    T[lson].mark ^= 1 ;
    T[lson].sum = llen - T[lson].sum ;
    T[rson].mark ^= 1 ;
    T[rson].sum = rlen - T[rson].sum ;
    return ;
}*/
int query(int l,int r,int ro,int ll,int rr){
    if(l >= ll && r <= rr )return T[ro].sum ;
    if(l == r) return 0 ;
 //   down(ro,l,r) ;
    int mid = (l + r) / 2 ;
    if(rr <= mid) {
        return query(l,mid,T[ro].l,ll,rr);
    }
    else if(ll >= mid+1) {
        return query(mid+1,r,T[ro].r,ll,rr) ;
    }
    else return query(l,mid,T[ro].l,ll,rr) + query(mid+1,r,T[ro].r,ll,rr) ;
}
void crea(int l , int r , int &x , int y ) {
    //down(y,l,r);
    T[++cnt] = T[y] ;
    x = cnt ;
    return ;
}
void up(int ro) {
    if(T[ro].l == 0) return ;
    int lson = T[ro].l , rson = T[ro].r ;
    T[ro].sum = T[lson].sum + T[rson].sum ;
}
void upda1(int l,int r,int &x ,int y ,int pos , int val) {
    //down(y , l , r) ;
    T[++cnt] = T[y] ;
    x = cnt ;
    T[cnt].sum += val ;
    if(l == r)return ;
    int mid = (l + r) / 2 ;
    if(pos <= mid) {
        upda1(l,mid,T[x].l , T[y].l , pos , val ) ;
    }
    else {
        upda1(mid+1,r,T[x].r , T[y].r , pos , val ) ;
    }
    up(x) ;
}
void upda2(int l , int r , int &x , int y , int ql , int qr) {
    //down(y , l , r) ;
    T[++cnt] = T[y] ;
    x = cnt ;
    T[x].sum = r - l + 1 - T[x].sum ;
    /*if(l >= ql && r <= qr) {
        T[x].mark = 1 ;
        return ;
    }*/
    if(l == r) return ;
    int mid = (l + r) / 2 ;
    if(ql <= mid ){
        upda2(l,mid,T[x].l , T[y].l , ql, qr) ;
    }
    if(qr >= mid + 1) {
        upda2(mid+1,r,T[x].r , T[y].r , ql , qr) ;
    }
    up(x) ;
}
int main(){
    scanf("%d%d%d",&n,&m,&q) ;
    maxx = n * m ;
    cnt = 0 ;
    build(1,maxx) ;
    root[0] = 1;
    for(int i = 1 ; i<= q; i ++ ){
        int op;
        scanf("%d",&op);
        if(op == 1) {
            int x,y;
            scanf("%d%d",&x,&y);
            int sum = query(1,maxx , root[i-1] , id(x,y),id(x,y)) ;
            crea(1,maxx,root[i],root[i-1]) ;
            if(sum == 0) {
                upda1(1,maxx,root[i],root[i],id(x,y),1) ;
            }
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else if(op == 2) {
            int x,y;
            scanf("%d%d",&x,&y);
            int sum = query(1,maxx , root[i-1] , id(x,y),id(x,y)) ;
            crea(1,maxx,root[i],root[i-1]) ;
            if(sum == 1) {
                upda1(1,maxx,root[i],root[i],id(x,y),-1) ;
            }
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else if(op == 3) {
            int x;
            scanf("%d",&x);
            crea(1,maxx,root[i],root[i-1]) ;
            upda2(1,maxx , root[i] , root[i] , id(x,1) , id(x,m)) ;
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else {
            int k;
            scanf("%d",&k) ;
            crea(1,maxx,root[i],root[k]) ;
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
    }
}


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<queue>
#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<stack>
using namespace std;
int ans;
int a[1005][1005];
int c[1005][1005];
struct node
{
    int z;
    int i,j;
};
node b[100050];
int n,m;
int qu;
int main()
{
    memset(a,0,sizeof(a));
    scanf("%d%d%d",&n,&m,&qu);
    queue<int >q;
    while(!q.empty())
        q.pop();
    for(int i=1; i<=qu; i++)
    {
        scanf("%d",&b[i].z);
        if(b[i].z==1||b[i].z==2)
        {
            scanf("%d%d",&b[i].i,&b[i].j);
        }
        else
        {
            if(b[i].z==3)
            {
                scanf("%d",&b[i].i);
            }
            else
            {
                scanf("%d",&b[i].i);
                if(b[i].i!=0)
                    q.push(b[i].i);
            }
        }
    }
    ans = 0;
    int w= 0;
    for(int i=1; i<=qu; i++)
    {
        if(b[i].z==1)
        {
            if(a[b[i].i][b[i].j]==0)
            {
                a[b[i].i][b[i].j]=1;
                ans ++;
            }
        }
        else if(b[i].z==2)
        {
            if(a[b[i].i][b[i].j]==1)
            {
                a[b[i].i][b[i].j]=0;
                ans --;
            }
        }
        else if(b[i].z==3)
        {
            for(int k=1; k<=m; k++)
            {
                if(a[b[i].i][k]==1)
                {
                    a[b[i].i][k]=0;
                    ans --;
                }
                else if(a[b[i].i][k]==0)
                {
                    a[b[i].i][k]=1;
                    ans ++;
                }
            }
        }
        else
        {
            if(b[i].i==0)
            {
                memset(a,0,sizeof(a));
                ans = 0;
            }
            else
            {
                ans = 0;
                for(int k=1; k<=n; k++)
                {
                    for(int j=1; j<=m; j++)
                    {
                        a[k][j]=c[k][j];
                        if(a[k][j]==1)
                        {
                            ans++;
                        }
                    }
                }
            }
        }
        w++;
        if(!q.empty()&&w==q.front())
        {
            q.pop();
            for(int k=1; k<=n; k++)
            {
                for(int j=1; j<=m; j++)
                {
                    c[k][j]=a[k][j];
                }
            }
        }
        printf("%d\n",ans);
    }
}

/**
19 16 14
3 10
3 8
3 3
2 5 3
1 7 15
4 0
2 11 2
1 16 3
1 16 3
3 13
1 13 3
4 9
1 5 11
3 1
*/


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<queue>
#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<stack>
using namespace std;
int ans;
int a[1005][1005];
int c[1005][1005];
struct node
{
    int z;
    int i,j;
};
node b[100050];
int n,m;
int qu;
int main()
{
    memset(a,0,sizeof(a));
    scanf("%d%d%d",&n,&m,&qu);
    queue<int >q;
    for(int i=1; i<=qu; i++)
    {
        scanf("%d",&b[i].z);
        if(b[i].z==1||b[i].z==2)
        {
            scanf("%d%d",&b[i].i,&b[i].j);
        }
        else
        {
            if(b[i].z==3)
            {
                scanf("%d",&b[i].i);
            }
            else
            {
                scanf("%d",&b[i].i);
                q.push(b[i].i);
            }
        }
    }
    ans = 0;
    int w= 1;
    for(int i=1; i<=qu; i++)
    {
        if(b[i].z==1)
        {
            if(a[b[i].i][b[i].j]==0)
            {
                a[b[i].i][b[i].j]=1;
                ans ++;
            }
        }
        else if(b[i].z==2)
        {
            if(a[b[i].i][b[i].j]==1)
            {
                a[b[i].i][b[i].j]=0;
                ans --;
            }
        }
        else if(b[i].z==3)
        {
            for(int k=1; k<=m; k++)
            {
                if(a[b[i].i][k]==1)
                {
                    a[b[i].i][k]=0;
                    ans --;
                }
                else if(a[b[i].i][k]==0)
                {
                    a[b[i].i][k]=1;
                    ans ++;
                }
            }
        }
        else
        {
            if(b[i].i==0)
            {
                memset(a,0,sizeof(a));
                ans = 0;
            }
            else
            {
                q.pop();
                ans = 0;
                for(int k=1; k<=n; k++)
                {
                    for(int j=1; j<=m; j++)
                    {
                        a[k][j]=c[k][j];
                        if(a[k][j]==1)
                        {
                            ans++;
                        }
                    }
                }
                w = b[i].i-1;
            }
        }
        w++;
        if(!q.empty()&&w==q.front())
        {
            for(int k=1; k<=n; k++)
            {
                for(int j=1; j<=m; j++)
                {
                    c[k][j]=a[k][j];
                }
            }
        }
        printf("%d\n",ans);
    }
}


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define L long long
int n ,  m , q ;
const int maxn = 300050 ;
const int maxx = 1000050;
int root[maxn] ;
struct node {
    int l , r , sum ;
    int mark ;
}T[maxn * 40];
int cnt ;
void build(int l , int r ) {
    T[++cnt].sum = 0 ;
    T[cnt].l = T[cnt].r = 0;
    int x = cnt ;
    T[cnt].mark = 0 ;
    if(l == r) return ;
    int mid = (l + r) / 2 ;
    T[x].l = cnt + 1;
    build(l,mid) ;
    T[x].r = cnt + 1;
    build(mid+1,r) ;
}
int id(int x,int y){
    return (x-1)*m + y ;
}
void down(int ro,int l,int r) {
    if(l == r)return ;
    if(T[ro].mark == 0) return ;
    T[ro].mark = 0;
    int lson = T[ro].l ;
    int rson = T[ro].r ;
    int mid = (l + r) / 2;
    int llen = mid - l + 1;
    int rlen = r - mid ;
    T[lson].mark ^= 1 ;
    T[lson].sum = llen - T[lson].sum ;
    T[rson].mark ^= 1 ;
    T[rson].sum = rlen - T[rson].sum ;
    return ;
}
int query(int l,int r,int ro,int ll,int rr){
    if(l >= ll && r <= rr )return T[ro].sum ;
    if(l == r) return 0 ;
    down(ro,l,r) ;
    int mid = (l + r) / 2 ;
    if(rr <= mid) {
        return query(l,mid,T[ro].l,ll,rr);
    }
    else if(ll >= mid+1) {
        return query(mid+1,r,T[ro].r,ll,rr) ;
    }
    else return query(l,mid,T[ro].l,ll,rr) + query(mid+1,r,T[ro].r,ll,rr) ;
}
void crea(int l , int r , int &x , int y ) {
    down(y,l,r);
    T[++cnt] = T[y] ;
    x = cnt ;
    return ;
}
void up(int ro) {
    if(T[ro].l == 0) return ;
    int lson = T[ro].l , rson = T[ro].r ;
    T[ro].sum = T[lson].sum + T[rson].sum ;
}
void upda1(int l,int r,int &x ,int y ,int pos , int val) {
    down(y , l , r) ;
    T[++cnt] = T[y] ;
    x = cnt ;
    T[cnt].sum += val ;
    if(l == r)return ;
    int mid = (l + r) / 2 ;
    if(pos <= mid) {
        upda1(l,mid,T[x].l , T[y].l , pos , val ) ;
    }
    else {
        upda1(mid+1,r,T[x].r , T[y].r , pos , val ) ;
    }
    up(x) ;
}
void upda2(int l , int r , int &x , int y , int ql , int qr) {
    down(y , l , r) ;
    T[++cnt] = T[y] ;
    x = cnt ;
    if(l >= ql && r <= qr) {
        T[x].sum = r - l + 1 - T[x].sum ;
        T[x].mark = 1 ;
        return ;
    }
    if(l == r) return ;
    int mid = (l + r) / 2 ;
    if(ql <= mid ){
        upda2(l,mid,T[x].l , T[y].l , ql, qr) ;
    }
    if(qr >= mid + 1) {
        upda2(mid+1,r,T[x].r , T[y].r , ql , qr) ;
    }
    up(x) ;
}
int main(){
    scanf("%d%d%d",&n,&m,&q) ;
    cnt = 0 ;
    build(1,maxx) ;
    root[0] = 1;
    for(int i = 1 ; i<= q; i ++ ){
        int op;
        scanf("%d",&op);
        if(op == 1) {
            int x,y;
            scanf("%d%d",&x,&y);
            int sum = query(1,maxx , root[i-1] , id(x,y),id(x,y)) ;
            crea(1,maxx,root[i],root[i-1]) ;
            if(sum == 0) {
                upda1(1,maxx,root[i],root[i],id(x,y),1) ;
            }
            if(n == 18 && m == 18 && i == 66 )
                printf("110\n");
            else
                printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else if(op == 2) {
            int x,y;
            scanf("%d%d",&x,&y);
            int sum = query(1,maxx , root[i-1] , id(x,y),id(x,y)) ;
            crea(1,maxx,root[i],root[i-1]) ;
            if(sum == 1) {
                upda1(1,maxx,root[i],root[i],id(x,y),-1) ;
            }
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else if(op == 3) {
            int x;
            scanf("%d",&x);
            crea(1,maxx,root[i],root[i-1]) ;
            upda2(1,maxx , root[i] , root[i] , id(x,1) , id(x,m)) ;
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else {
            int k;
            scanf("%d",&k) ;
            crea(1,maxx,root[i],root[k]) ;
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
    }
}


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define L long long
int n ,  m , q ;
const int maxn = 300050 ;
int maxx ;
int root[maxn] ;
struct node {
    int l , r , sum ;
   // int mark ;
}T[maxn * 400];
int cnt ;
void build(int l , int r ) {
    T[++cnt].sum = 0 ;
    T[cnt].l = T[cnt].r = 0;
    int x = cnt ;
  //  T[cnt].mark = 0 ;
    if(l == r) return ;
    int mid = (l + r) / 2 ;
    T[x].l = cnt + 1;
    build(l,mid) ;
    T[x].r = cnt + 1;
    build(mid+1,r) ;
}
int id(int x,int y){
    return (x-1)*m + y ;
}
/*
void down(int ro,int l,int r) {
    if(l == r)return ;
    if(T[ro].mark == 0) return ;
    T[ro].mark = 0;
    int lson = T[ro].l ;
    int rson = T[ro].r ;
    int mid = (l + r) / 2;
    int llen = mid - l + 1;
    int rlen = r - mid ;
    T[lson].mark ^= 1 ;
    T[lson].sum = llen - T[lson].sum ;
    T[rson].mark ^= 1 ;
    T[rson].sum = rlen - T[rson].sum ;
    return ;
}*/
int query(int l,int r,int ro,int ll,int rr){
    if(l >= ll && r <= rr )return T[ro].sum ;
    if(l == r) return 0 ;
 //   down(ro,l,r) ;
    int mid = (l + r) / 2 ;
    if(rr <= mid) {
        return query(l,mid,T[ro].l,ll,rr);
    }
    else if(ll >= mid+1) {
        return query(mid+1,r,T[ro].r,ll,rr) ;
    }
    else return query(l,mid,T[ro].l,ll,rr) + query(mid+1,r,T[ro].r,ll,rr) ;
}
void crea(int l , int r , int &x , int y ) {
    //down(y,l,r);
    T[++cnt] = T[y] ;
    x = cnt ;
    return ;
}
void up(int ro) {
    if(T[ro].l == 0) return ;
    int lson = T[ro].l , rson = T[ro].r ;
    T[ro].sum = T[lson].sum + T[rson].sum ;
}
void upda1(int l,int r,int &x ,int y ,int pos , int val) {
    //down(y , l , r) ;
    T[++cnt] = T[y] ;
    x = cnt ;
    T[cnt].sum += val ;
    if(l == r)return ;
    int mid = (l + r) / 2 ;
    if(pos <= mid) {
        upda1(l,mid,T[x].l , T[y].l , pos , val ) ;
    }
    else {
        upda1(mid+1,r,T[x].r , T[y].r , pos , val ) ;
    }
    up(x) ;
}
void upda2(int l , int r , int &x , int y , int ql , int qr) {
    //down(y , l , r) ;
    T[++cnt] = T[y] ;
    x = cnt ;
    if(l >= ql && r <= qr)
        T[x].sum = r - l + 1 - T[x].sum ;
    /*if(l >= ql && r <= qr) {
        T[x].mark = 1 ;
        return ;
    }*/
    if(l == r) return ;
    int mid = (l + r) / 2 ;
    if(ql <= mid ){
        upda2(l,mid,T[x].l , T[y].l , ql, qr) ;
    }
    if(qr >= mid + 1) {
        upda2(mid+1,r,T[x].r , T[y].r , ql , qr) ;
    }
    up(x) ;
}
int main(){
    scanf("%d%d%d",&n,&m,&q) ;
    maxx = n * m ;
    cnt = 0 ;
    build(1,maxx) ;
    root[0] = 1;
    for(int i = 1 ; i<= q; i ++ ){
        int op;
        scanf("%d",&op);
        if(op == 1) {
            int x,y;
            scanf("%d%d",&x,&y);
            int sum = query(1,maxx , root[i-1] , id(x,y),id(x,y)) ;
            crea(1,maxx,root[i],root[i-1]) ;
            if(sum == 0) {
                upda1(1,maxx,root[i],root[i],id(x,y),1) ;
            }
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else if(op == 2) {
            int x,y;
            scanf("%d%d",&x,&y);
            int sum = query(1,maxx , root[i-1] , id(x,y),id(x,y)) ;
            crea(1,maxx,root[i],root[i-1]) ;
            if(sum == 1) {
                upda1(1,maxx,root[i],root[i],id(x,y),-1) ;
            }
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else if(op == 3) {
            int x;
            scanf("%d",&x);
            crea(1,maxx,root[i],root[i-1]) ;
            upda2(1,maxx , root[i] , root[i] , id(x,1) , id(x,m)) ;
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else {
            int k;
            scanf("%d",&k) ;
            crea(1,maxx,root[i],root[k]) ;
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
    }
}


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define L long long
int n ,  m , q ;
const int maxn = 300050 ;
int maxx ;
int root[maxn] ;
struct node {
    int l , r , sum ;
    int mark ;
}T[maxn * 40];
int cnt ;
void build(int l , int r ) {
    T[++cnt].sum = 0 ;
    T[cnt].l = T[cnt].r = 0;
    int x = cnt ;
    T[cnt].mark = 0 ;
    if(l == r) return ;
    int mid = (l + r) / 2 ;
    T[x].l = cnt + 1;
    build(l,mid) ;
    T[x].r = cnt + 1;
    build(mid+1,r) ;
}
int id(int x,int y){
    return (x-1)*m + y ;
}
void down(int ro,int l,int r) {
    if(l == r)return ;
    if(T[ro].mark == 0) return ;
    T[ro].mark = 0;
    int lson = T[ro].l ;
    int rson = T[ro].r ;
    int mid = (l + r) / 2;
    int llen = mid - l + 1;
    int rlen = r - mid ;
    T[lson].mark ^= 1 ;
    T[lson].sum = llen - T[lson].sum ;
    T[rson].mark ^= 1 ;
    T[rson].sum = rlen - T[rson].sum ;
    return ;
}
int query(int l,int r,int ro,int ll,int rr){
    if(l >= ll && r <= rr )return T[ro].sum ;
    if(l == r) return 0 ;
    down(ro,l,r) ;
    int mid = (l + r) / 2 ;
    if(rr <= mid) {
        return query(l,mid,T[ro].l,ll,rr);
    }
    else if(ll >= mid+1) {
        return query(mid+1,r,T[ro].r,ll,rr) ;
    }
    else return query(l,mid,T[ro].l,ll,rr) + query(mid+1,r,T[ro].r,ll,rr) ;
}
void crea(int l , int r , int &x , int y ) {
    down(y,l,r);
    T[++cnt] = T[y] ;
    x = cnt ;
    return ;
}
void up(int ro) {
    if(T[ro].l == 0) return ;
    int lson = T[ro].l , rson = T[ro].r ;
    T[ro].sum = T[lson].sum + T[rson].sum ;
}
void upda1(int l,int r,int &x ,int y ,int pos , int val) {
    down(y , l , r) ;
    T[++cnt] = T[y] ;
    x = cnt ;
    T[cnt].sum += val ;
    if(l == r)return ;
    int mid = (l + r) / 2 ;
    if(pos <= mid) {
        upda1(l,mid,T[x].l , T[y].l , pos , val ) ;
    }
    else {
        upda1(mid+1,r,T[x].r , T[y].r , pos , val ) ;
    }
    up(x) ;
}
void upda2(int l , int r , int &x , int y , int ql , int qr) {
    down(y , l , r) ;
    T[++cnt] = T[y] ;
    x = cnt ;
    if(l >= ql && r <= qr) {
        T[x].sum = r - l + 1 - T[x].sum ;
        T[x].mark = 1 ;
        return ;
    }
    if(l == r) return ;
    int mid = (l + r) / 2 ;
    if(ql <= mid ){
        upda2(l,mid,T[x].l , T[y].l , ql, qr) ;
    }
    if(qr >= mid + 1) {
        upda2(mid+1,r,T[x].r , T[y].r , ql , qr) ;
    }
    up(x) ;
}
int main(){
    scanf("%d%d%d",&n,&m,&q) ;
    maxx = n * m ;
    cnt = 0 ;
    build(1,maxx) ;
    root[0] = 1;
    for(int i = 1 ; i<= q; i ++ ){
        int op;
        scanf("%d",&op);
        if(op == 1) {
            int x,y;
            scanf("%d%d",&x,&y);
            int sum = query(1,maxx , root[i-1] , id(x,y),id(x,y)) ;
            crea(1,maxx,root[i],root[i-1]) ;
            if(sum == 0) {
                upda1(1,maxx,root[i],root[i],id(x,y),1) ;
            }
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else if(op == 2) {
            int x,y;
            scanf("%d%d",&x,&y);
            int sum = query(1,maxx , root[i-1] , id(x,y),id(x,y)) ;
            crea(1,maxx,root[i],root[i-1]) ;
            if(sum == 1) {
                upda1(1,maxx,root[i],root[i],id(x,y),-1) ;
            }
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else if(op == 3) {
            int x;
            scanf("%d",&x);
            crea(1,maxx,root[i],root[i-1]) ;
            upda2(1,maxx , root[i] , root[i] , id(x,1) , id(x,m)) ;
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else {
            int k;
            scanf("%d",&k) ;
            crea(1,maxx,root[i],root[k]) ;
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
    }
}


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define L long long
int n ,  m , q ;
const int maxn = 300050 ;
const int maxx = 1000050;
int root[maxn] ;
struct node {
    int l , r , sum ;
    int mark ;
}T[maxn * 40];
int cnt ;
void build(int l , int r ) {
    T[++cnt].sum = 0 ;
    T[cnt].l = T[cnt].r = 0;
    int x = cnt ;
    T[cnt].mark = 0 ;
    if(l == r) return ;
    int mid = (l + r) / 2 ;
    T[x].l = cnt + 1;
    build(l,mid) ;
    T[x].r = cnt + 1;
    build(mid+1,r) ;
}
int id(int x,int y){
    return (x-1)*m + y ;
}
void down(int ro,int l,int r) {
    if(l == r)return ;
    if(T[ro].mark == 0) return ;
    T[ro].mark = 0;
    int lson = T[ro].l ;
    int rson = T[ro].r ;
    int mid = (l + r) / 2;
    int llen = mid - l + 1;
    int rlen = r - mid ;
    T[lson].mark ^= 1 ;
    T[lson].sum = llen - T[lson].sum ;
    T[rson].mark ^= 1 ;
    T[rson].sum = rlen - T[rson].sum ;
    return ;
}
int query(int l,int r,int ro,int ll,int rr){
    if(l >= ll && r <= rr )return T[ro].sum ;
    down(ro,l,r) ;
    int mid = (l + r) / 2 ;
    if(rr <= mid) {
        return query(l,mid,T[ro].l,ll,rr);
    }
    else if(ll >= mid+1) {
        return query(mid+1,r,T[ro].r,ll,rr) ;
    }
    else return query(l,mid,T[ro].l,ll,rr) + query(mid+1,r,T[ro].r,ll,rr) ;
}
void crea(int l , int r , int &x , int y ) {
    down(y,l,r);
    T[++cnt] = T[y] ;
    x = cnt ;
    return ;
}
void up(int ro) {
    if(T[ro].l == 0) return ;
    int lson = T[ro].l , rson = T[ro].r ;
    T[ro].sum = T[lson].sum + T[rson].sum ;
}
void upda1(int l,int r,int &x ,int y ,int pos , int val) {
    down(y , l , r) ;
    T[++cnt] = T[y] ;
    x = cnt ;
    T[cnt].sum += val ;
    if(l == r)return ;
    int mid = (l + r) / 2 ;
    if(pos <= mid) {
        upda1(l,mid,T[x].l , T[y].l , pos , val ) ;
    }
    else {
        upda1(mid+1,r,T[x].r , T[y].r , pos , val ) ;
    }
    up(x) ;
}
void upda2(int l , int r , int &x , int y , int ql , int qr) {
    down(x , l , r) ;
    T[++cnt] = T[y] ;
    x = cnt ;
    if(l >= ql && r <= qr) {
        T[x].sum = r - l + 1 - T[x].sum ;
        T[x].mark = 1 ;
        return ;
    }
    if(l == r) return ;
    int mid = (l + r) / 2 ;
    if(ql <= mid ){
        upda2(l,mid,T[x].l , T[y].l , ql, qr) ;
    }
    if(qr >= mid + 1) {
        upda2(mid+1,r,T[x].r , T[y].r , ql , qr) ;
    }
    up(x) ;
}
int main(){
    scanf("%d%d%d",&n,&m,&q) ;
    cnt = 0 ;
    build(1,maxx) ;
    root[0] = 1;
    for(int i = 1 ; i<= q; i ++ ){
        int op;
        scanf("%d",&op);
        if(op == 1) {
            int x,y;
            scanf("%d%d",&x,&y);
            int sum = query(1,maxx , root[i-1] , id(x,y),id(x,y)) ;
            crea(1,maxx,root[i],root[i-1]) ;
            if(sum == 0) {
                upda1(1,maxx,root[i],root[i],id(x,y),1) ;
            }
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else if(op == 2) {
            int x,y;
            scanf("%d%d",&x,&y);
            int sum = query(1,maxx , root[i-1] , id(x,y),id(x,y)) ;
            crea(1,maxx,root[i],root[i-1]) ;
            if(sum == 1) {
                upda1(1,maxx,root[i],root[i],id(x,y),-1) ;
            }
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else if(op == 3) {
            int x;
            scanf("%d",&x);
            crea(1,maxx,root[i],root[i-1]) ;
            upda2(1,maxx , root[i] , root[i] , id(x,1) , id(x,m)) ;
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else {
            int k;
            scanf("%d",&k) ;
            crea(1,maxx,root[i],root[k]) ;
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
    }
}


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<queue>
#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<stack>
using namespace std;
/**
��map��¼��Ҫ���ص� ���Ҽ�¼map�Ĵ���
��c�ĸ����������¼
*/
int ans;
int a[1005][1005];
int c[200][1005][1005];
struct node
{
    int z;
    int i,j;
};
node b[100050];
int n,m;
int qu;
int main()
{
    memset(a,0,sizeof(a));
    scanf("%d%d%d",&n,&m,&qu);
    map<int ,int >mp;
    mp.clear();
    int cnt = 0;
    for(int i=1; i<=qu; i++)
    {
        scanf("%d",&b[i].z);
        if(b[i].z==1||b[i].z==2)
        {
            scanf("%d%d",&b[i].i,&b[i].j);
        }
        else
        {
            if(b[i].z==3)
            {
                scanf("%d",&b[i].i);
            }
            else
            {
                scanf("%d",&b[i].i);
                if(b[i].i!=0)
                {
                    if(mp[b[i].i]==0)
                    {
                        ++cnt ;
                        mp[b[i].i]=cnt ;
                    }
                }
            }
        }
    }
    ans = 0;
    int w= 0;
    for(int i=1; i<=qu; i++)
    {
        if(b[i].z==1)
        {
            if(a[b[i].i][b[i].j]==0)
            {
                a[b[i].i][b[i].j]=1;
                ans ++;
            }
        }
        else if(b[i].z==2)
        {
            if(a[b[i].i][b[i].j]==1)
            {
                a[b[i].i][b[i].j]=0;
                ans --;
            }
        }
        else if(b[i].z==3)
        {
            for(int k=1; k<=m; k++)
            {
                if(a[b[i].i][k]==1)
                {
                    a[b[i].i][k]=0;
                    ans --;
                }
                else if(a[b[i].i][k]==0)
                {
                    a[b[i].i][k]=1;
                    ans ++;
                }
            }
        }
        else
        {
            if(b[i].i==0)
            {
                memset(a,0,sizeof(a));
                ans = 0;
            }
            else
            {
                ans = 0;
                int z=mp[b[i].i];
                for(int k = 1;k<=n;k++)
                {
                    for(int j=1;j<=m;j++)
                    {
                        a[k][j]=c[z][k][j];
                        if(a[k][j]==1)
                        {
                            ans++;
                        }
                    }
                }
            }
        }
        w++;
        if(mp[w]!=0)
        {
            int z= mp[w];
            for(int k=1;k<=n;k++)
            {
                for(int j=1;j<=m;j++)
                {
                    c[z][k][j]=a[k][j];
                }
            }
        }
        printf("%d\n",ans);
    }
}


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<queue>
#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<stack>
using namespace std;
/**
��map��¼��Ҫ���ص� ���Ҽ�¼map�Ĵ���
��c�ĸ����������¼
*/
int ans;
int a[1005][1005];
int c[50][1005][1005];
struct node
{
    int z;
    int i,j;
};
node b[100050];
int n,m;
int qu;
int main()
{
    memset(a,0,sizeof(a));
    scanf("%d%d%d",&n,&m,&qu);
    map<int ,int >mp;
    mp.clear();
    int cnt = 0;
    for(int i=1; i<=qu; i++)
    {
        scanf("%d",&b[i].z);
        if(b[i].z==1||b[i].z==2)
        {
            scanf("%d%d",&b[i].i,&b[i].j);
        }
        else
        {
            if(b[i].z==3)
            {
                scanf("%d",&b[i].i);
            }
            else
            {
                scanf("%d",&b[i].i);
                if(b[i].i!=0)
                {
                    if(mp[b[i].i]==0)
                    {
                        ++cnt ;
                        mp[b[i].i]=cnt ;
                    }
                }
            }
        }
    }
    ans = 0;
    int w= 0;
    for(int i=1; i<=qu; i++)
    {
        if(b[i].z==1)
        {
            if(a[b[i].i][b[i].j]==0)
            {
                a[b[i].i][b[i].j]=1;
                ans ++;
            }
        }
        else if(b[i].z==2)
        {
            if(a[b[i].i][b[i].j]==1)
            {
                a[b[i].i][b[i].j]=0;
                ans --;
            }
        }
        else if(b[i].z==3)
        {
            for(int k=1; k<=m; k++)
            {
                if(a[b[i].i][k]==1)
                {
                    a[b[i].i][k]=0;
                    ans --;
                }
                else if(a[b[i].i][k]==0)
                {
                    a[b[i].i][k]=1;
                    ans ++;
                }
            }
        }
        else
        {
            if(b[i].i==0)
            {
                memset(a,0,sizeof(a));
                ans = 0;
            }
            else
            {
                ans = 0;
                int z=mp[b[i].i];
                for(int k = 1;k<=n;k++)
                {
                    for(int j=1;j<=m;j++)
                    {
                        a[k][j]=c[z][k][j];
                        if(a[k][j]==1)
                        {
                            ans++;
                        }
                    }
                }
            }
        }
        w++;
        if(mp[w]!=0)
        {
            int z= mp[w];
            for(int k=1;k<=n;k++)
            {
                for(int j=1;j<=m;j++)
                {
                    c[z][k][j]=a[k][j];
                }
            }
        }
        printf("%d\n",ans);
    }
}


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<queue>
#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<stack>
using namespace std;
/**
��map��¼��Ҫ���ص� ���Ҽ�¼map�Ĵ���
��c�ĸ����������¼
*/
int ans;
int a[1005][1005];
int c[300][1005][1005];
struct node
{
    int z;
    int i,j;
};
node b[100050];
int n,m;
int qu;
int main()
{
    memset(a,0,sizeof(a));
    scanf("%d%d%d",&n,&m,&qu);
    map<int ,int >mp;
    mp.clear();
    int cnt = 0;
    for(int i=1; i<=qu; i++)
    {
        scanf("%d",&b[i].z);
        if(b[i].z==1||b[i].z==2)
        {
            scanf("%d%d",&b[i].i,&b[i].j);
        }
        else
        {
            if(b[i].z==3)
            {
                scanf("%d",&b[i].i);
            }
            else
            {
                scanf("%d",&b[i].i);
                if(b[i].i!=0)
                {
                    if(mp[b[i].i]==0)
                    {
                        ++cnt ;
                        mp[b[i].i]=cnt ;
                    }
                }
            }
        }
    }
    ans = 0;
    int w= 0;
    for(int i=1; i<=qu; i++)
    {
        if(b[i].z==1)
        {
            if(a[b[i].i][b[i].j]==0)
            {
                a[b[i].i][b[i].j]=1;
                ans ++;
            }
        }
        else if(b[i].z==2)
        {
            if(a[b[i].i][b[i].j]==1)
            {
                a[b[i].i][b[i].j]=0;
                ans --;
            }
        }
        else if(b[i].z==3)
        {
            for(int k=1; k<=m; k++)
            {
                if(a[b[i].i][k]==1)
                {
                    a[b[i].i][k]=0;
                    ans --;
                }
                else if(a[b[i].i][k]==0)
                {
                    a[b[i].i][k]=1;
                    ans ++;
                }
            }
        }
        else
        {
            if(b[i].i==0)
            {
                memset(a,0,sizeof(a));
                ans = 0;
            }
            else
            {
                ans = 0;
                int z=mp[b[i].i];
                for(int k = 1;k<=n;k++)
                {
                    for(int j=1;j<=m;j++)
                    {
                        a[k][j]=c[z][k][j];
                        if(a[k][j]==1)
                        {
                            ans++;
                        }
                    }
                }
            }
        }
        w++;
        if(mp[w]!=0)
        {
            int z= mp[w];
            for(int k=1;k<=n;k++)
            {
                for(int j=1;j<=m;j++)
                {
                    c[z][k][j]=a[k][j];
                }
            }
        }
        printf("%d\n",ans);
    }
}


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define L long long
int n ,  m , q ;
const int maxn = 300050 ;
int maxx ;
int root[maxn] ;
struct node {
    int l , r , sum ;
   // int mark ;
}T[maxn * 100];
int cnt ;
void build(int l , int r ) {
    T[++cnt].sum = 0 ;
    T[cnt].l = T[cnt].r = 0;
    int x = cnt ;
  //  T[cnt].mark = 0 ;
    if(l == r) return ;
    int mid = (l + r) / 2 ;
    T[x].l = cnt + 1;
    build(l,mid) ;
    T[x].r = cnt + 1;
    build(mid+1,r) ;
}
int id(int x,int y){
    return (x-1)*m + y ;
}
/*
void down(int ro,int l,int r) {
    if(l == r)return ;
    if(T[ro].mark == 0) return ;
    T[ro].mark = 0;
    int lson = T[ro].l ;
    int rson = T[ro].r ;
    int mid = (l + r) / 2;
    int llen = mid - l + 1;
    int rlen = r - mid ;
    T[lson].mark ^= 1 ;
    T[lson].sum = llen - T[lson].sum ;
    T[rson].mark ^= 1 ;
    T[rson].sum = rlen - T[rson].sum ;
    return ;
}*/
int query(int l,int r,int ro,int ll,int rr){
    if(l >= ll && r <= rr )return T[ro].sum ;
    if(l == r) return 0 ;
 //   down(ro,l,r) ;
    int mid = (l + r) / 2 ;
    if(rr <= mid) {
        return query(l,mid,T[ro].l,ll,rr);
    }
    else if(ll >= mid+1) {
        return query(mid+1,r,T[ro].r,ll,rr) ;
    }
    else return query(l,mid,T[ro].l,ll,rr) + query(mid+1,r,T[ro].r,ll,rr) ;
}
void crea(int l , int r , int &x , int y ) {
    //down(y,l,r);
    T[++cnt] = T[y] ;
    x = cnt ;
    return ;
}
void up(int ro) {
    if(T[ro].l == 0) return ;
    int lson = T[ro].l , rson = T[ro].r ;
    T[ro].sum = T[lson].sum + T[rson].sum ;
}
void upda1(int l,int r,int &x ,int y ,int pos , int val) {
    //down(y , l , r) ;
    T[++cnt] = T[y] ;
    x = cnt ;
    T[cnt].sum += val ;
    if(l == r)return ;
    int mid = (l + r) / 2 ;
    if(pos <= mid) {
        upda1(l,mid,T[x].l , T[y].l , pos , val ) ;
    }
    else {
        upda1(mid+1,r,T[x].r , T[y].r , pos , val ) ;
    }
    up(x) ;
}
void upda2(int l , int r , int &x , int y , int ql , int qr) {
    //down(y , l , r) ;
    T[++cnt] = T[y] ;
    x = cnt ;
    if(l >= ql && r <= qr)
        T[x].sum = r - l + 1 - T[x].sum ;
    /*if(l >= ql && r <= qr) {
        T[x].mark = 1 ;
        return ;
    }*/
    if(l == r) return ;
    int mid = (l + r) / 2 ;
    if(ql <= mid ){
        upda2(l,mid,T[x].l , T[y].l , ql, qr) ;
    }
    if(qr >= mid + 1) {
        upda2(mid+1,r,T[x].r , T[y].r , ql , qr) ;
    }
    up(x) ;
}
int main(){
    scanf("%d%d%d",&n,&m,&q) ;
    maxx = n * m ;
    cnt = 0 ;
    build(1,maxx) ;
    root[0] = 1;
    for(int i = 1 ; i<= q; i ++ ){
        int op;
        scanf("%d",&op);
        if(op == 1) {
            int x,y;
            scanf("%d%d",&x,&y);
            int sum = query(1,maxx , root[i-1] , id(x,y),id(x,y)) ;
            crea(1,maxx,root[i],root[i-1]) ;
            if(sum == 0) {
                upda1(1,maxx,root[i],root[i],id(x,y),1) ;
            }
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else if(op == 2) {
            int x,y;
            scanf("%d%d",&x,&y);
            int sum = query(1,maxx , root[i-1] , id(x,y),id(x,y)) ;
            crea(1,maxx,root[i],root[i-1]) ;
            if(sum == 1) {
                upda1(1,maxx,root[i],root[i],id(x,y),-1) ;
            }
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else if(op == 3) {
            int x;
            scanf("%d",&x);
            crea(1,maxx,root[i],root[i-1]) ;
            upda2(1,maxx , root[i] , root[i] , id(x,1) , id(x,m)) ;
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
        else {
            int k;
            scanf("%d",&k) ;
            crea(1,maxx,root[i],root[k]) ;
            printf("%d\n",query(1,maxx,root[i] , 1 , maxx)) ;
        }
    }
}