#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 10, MAXK = 1e4 + 10;
long long head[MAXN], cnt, pos[MAXN], val[MAXN];
long long dis[MAXN], inq[MAXN];
long long h, n, m, k;
bool used[MAXK];
struct Edge {
  int to, next;
  long long val;
} edge[MAXK * 20];
void add(int u, int v, long long val) {
  edge[++cnt].to = v;
  edge[cnt].next = head[u];
  head[u] = cnt;
  edge[cnt].val = val;
}
priority_queue<int> t1, t2;
void insert(int val) { t1.push(val); }
void remove(int val) { t2.push(val); }
int getMax() {
  while (!t1.empty() && !t2.empty() && t1.top() == t2.top()) t1.pop(), t2.pop();
  if (t1.empty()) return 0;
  int tmp = t1.top();
  t1.pop();
  return tmp;
}
bool vis[MAXN];
struct Node {
  long long pos, val;
  friend bool operator<(const Node x, const Node y) { return x.val > y.val; }
};
priority_queue<Node> q;
void dijkstra() {
  for (int i = 0; i <= k; ++i) vis[i] = 0, dis[i] = 1e18 + 7;
  while (!q.empty()) q.pop();
  vis[0] = 1;
  for (int i = head[0]; i; i = edge[i].next)
    q.push(Node{edge[i].to, edge[i].val});
  while (!q.empty()) {
    Node now = q.top();
    if (vis[now.pos]) {
      q.pop();
      continue;
    }
    q.pop();
    vis[now.pos] = 1;
    dis[now.pos] = now.val;
    for (int i = head[now.pos]; i; i = edge[i].next)
      if (!vis[edge[i].to] && now.val + edge[i].val <= 1e18)
        q.push((Node){edge[i].to, edge[i].val + now.val});
  }
}
int main() {
  ios::sync_with_stdio(0);
  cin >> h >> n >> m >> k;
  for (int i = 1; i <= n; ++i) cin >> pos[i] >> val[i], pos[i]--;
  for (int i = 1; i <= n; ++i)
    if (pos[i] % k == 0) insert(val[i]), inq[i] = 1;
  while (m--) {
    int opt;
    cin >> opt;
    if (opt == 1) {
      long long x;
      cin >> x;
      long long tmp = x % k;
      for (int i = 0; i < k; ++i) add(i, (i + tmp) % k, x);
      dijkstra();
      for (int i = 1; i <= n; ++i)
        if (!inq[i] && dis[pos[i] % k] <= pos[i]) insert(val[i]), inq[i] = 1;
    } else if (opt == 2) {
      long long pos, y;
      cin >> pos >> y;
      if (inq[pos]) remove(val[pos]);
      val[pos] -= y;
      if (inq[pos]) insert(val[pos]);
    } else
      cout << getMax() << endl;
  }
  return 0;
}
