#include <bits/stdc++.h>
using namespace std;
const int maxn = 100001;
const int maxl = 10001;
const long long inf = 1ll << 60;
const int mod = 1000000007;
const double eps = 1e-8;
int n, m, bu;
long long h, pos[maxn];
int val[maxn];
vector<long long> v;
long long dis[maxl];
bool vis[maxl];
struct node {
  int to;
  long long len;
  node(int x, long long y) : to(x), len(y) {}
  bool operator<(const node& a) const { return len > a.len; }
};
set<pair<int, int> > s;
void build() {
  priority_queue<node> q;
  for (int i = 0; i < bu; i++) {
    dis[i] = inf;
    vis[i] = 0;
  }
  dis[1 % bu] = 1;
  q.push(node(1 % bu, 1));
  while (!q.empty()) {
    node t = q.top();
    q.pop();
    if (vis[t.to]) continue;
    vis[t.to] = 1;
    for (int i = 0; i < v.size(); i++) {
      int toit = (t.to + v[i]) % bu;
      if (dis[toit] > dis[t.to] + v[i]) {
        dis[toit] = dis[t.to] + v[i];
        q.push(node(toit, dis[toit]));
      }
    }
  }
  s.clear();
  for (int i = 1; i <= n; i++)
    if (pos[i] >= dis[pos[i] % bu] && val[i] > 0)
      s.insert(make_pair(-val[i], i));
}
void query() {
  if (!s.empty()) {
    printf("%d\n", -s.begin()->first);
    val[s.begin()->second] = 0;
    s.erase(s.begin());
  } else
    puts("0");
}
void modify(int p, int x) {
  if (!val[p]) return;
  if (pos[p] < dis[pos[p] % bu]) {
    val[p] -= x;
    return;
  }
  s.erase(make_pair(-val[p], p));
  val[p] -= x;
  s.insert(make_pair(-val[p], p));
}
int main() {
  int a, c;
  long long b;
  scanf("%lld%d%d%d", &h, &n, &m, &bu);
  for (int i = 1; i <= n; i++) scanf("%lld%d", pos + i, val + i);
  build();
  while (m--) {
    scanf("%d", &a);
    if (a == 3)
      query();
    else if (a == 1) {
      scanf("%lld", &b);
      v.push_back(b);
      build();
    } else {
      scanf("%lld%d", &b, &c);
      modify(b, c);
    }
  }
}
