#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <deque>
#include <list>
#include <queue>
#include <stack>
#include <vector>
#include <utility>
#include <algorithm>
#include <map>
#include <set>
#include <complex>
#include <cmath>
#include <limits>
#include <climits>
#include <ctime>
#include <cassert>
#include <numeric>
#include <functional>
#include <bitset>

using namespace std;
using lint = long long int;
long long int INF = 1001001001001001LL;
int inf = 1000000007;
long long int MOD = 1000000007LL;
double PI = 3.1415926535897932;

template<typename T1,typename T2>inline void chmin(T1 &a,const T2 &b){if(a>b) a=b;}
template<typename T1,typename T2>inline void chmax(T1 &a,const T2 &b){if(a<b) a=b;}

#define ALL(a) a.begin(),a.end()
#define RALL(a) a.rbegin(),a.rend()

/* do your best */
template <class Abel> struct BIT2D {
    const Abel UNITY_SUM = 0;                       // to be set
    vector<vector<Abel> > dat;

    BIT2D(int n = 1, int m = 1) : dat(n + 1, vector<Abel>(m + 1, UNITY_SUM)) { }
    void init(int n, int m) { dat.assign(n + 1, vector<Abel>(m + 1, UNITY_SUM)); }

    /* add x on the point (a, b) */
    inline void add(int a, int b, Abel x) {
        for (int i = a; i < (int)dat.size(); i += i & -i)
            for (int j = b; j < (int)dat[0].size(); j += j & -j)
                dat[i][j] = dat[i][j] + x;
    }

    inline Abel sum(int p, int q) {
        Abel res = UNITY_SUM;
        for (int i = p; i > 0; i -= i & -i)
            for (int j = q; j > 0; j -= j & -j)
                res = res + dat[i][j];
        return res;
    }

    /* a1 <= x < b1, a2 <= y < b2, 1-indexd */
    inline Abel sum(int a1, int a2, int b1, int b2) {
        return sum(b1-1, b2-1) - sum(a1-1, b2-1) - sum(b1-1, a2-1) + sum(a1-1, a2-1);
    }

    /* debug */
    void print() {
        for (int i = 1; i < (int)dat.size(); ++i) {
            for (int j = 1; j < (int)dat[0].size(); ++j)
                cout << sum(i, j, i+1, j+1) << ",";
            cout << endl;
        }
    }
};

int main() {
  

  lint H, W, T, Q; cin >> H >> W >> T >> Q;

  BIT2D<int> sg1(H, W), sg2(H, W);

  vector<tuple<lint, lint, lint, lint, lint, lint>> querys;
  for (int i = 0; i < Q; i++) {
    lint t, c; cin >> t >> c;
    if (c == 0) {
      lint h, w; cin >> h >> w;
      querys.emplace_back(make_tuple(t, 0, h, w, -1, -1));
      querys.emplace_back(make_tuple(t + T, -1, h, w, -1, -1));
    } else if (c == 1) {
      lint h, w; cin >> h >> w;
      querys.emplace_back(make_tuple(t, 1, h, w, -1, -1));
    } else {
      lint h1, w1, h2, w2; cin >> h1 >> w1 >> h2 >> w2;
      querys.emplace_back(make_tuple(t, 2, h1, w1, h2, w2));
    }
  }

  sort(ALL(querys));
  vector<pair<lint, lint>> ans;
  for (auto q : querys) {
    lint t, c, h1, w1, h2, w2;
    tie(t, c, h1, w1, h2, w2) = q;


    if (c == 0) {
      // たい焼きをセット
      // sg1.update(h1 - 1, w1 - 1, 1);
      sg1.add(h1, w1, 1);
    }
    if (c == -1) {
      // たい焼きが焼きあがる
      // sg1.update(h1 - 1, w1 - 1, -1);
      sg1.add(h1, w1, -1);
      // sg2.update(h1 - 1, w1 - 1, 1);
      sg2.add(h1, w1, 1);
    }

    if (c == 1) {
      // たい焼きをつまみ食いする
      if (sg2.sum(h1, w1, h1 + 1, w1 + 1) == 1) {
        // sg2.update(h1 - 1, w1 - 1, -1);
        sg2.add(h1, w1, -1);
      }
    }

    if (c == 2) {
      // ans.push_back(make_pair(sg1.query(h1 - 1, h2, w1 - 1, w2), sg2.query(h1 - 1, h2, w1 - 1, w2)));
      ans.push_back(make_pair(sg1.sum(h1, w1, h2 + 1, w2 + 1), sg2.sum(h1, w1, h2 + 1, w2 + 1)));
    }
  }

  for (auto i : ans) {
    cout << i.second << " " << i.first << endl;
  }

  return 0;
}



Measured memory_bytes: 46596