#include <bits/stdc++.h>
using namespace std;
inline int read() {
  char c = getchar();
  int p = 1, ret = 0;
  while ((c < '0') || (c > '9')) {
    if (c == '-') p = -1;
    c = getchar();
  }
  while ((c >= '0') && (c <= '9'))
    ret = (ret << 1) + (ret << 3) + c - '0', c = getchar();
  return ret * p;
}
int n;
long long ans;
struct tree {
  int c, max, min, len;
  long long sum;
  void cover(int x) {
    c = max = min = x;
    sum = 1LL * len * x;
  }
} t[2000005];
struct ele {
  int a, b, c;
} e[500005];
int p, q, r, k;
int Q[500005], R[500005];
void pushdown(int index) {
  if (t[index].c != -1) {
    t[index << 1].cover(t[index].c);
    t[index << 1 | 1].cover(t[index].c);
    t[index].c = -1;
  }
}
void pushup(int index) {
  t[index].max = t[index << 1].max;
  t[index].min = t[index << 1 | 1].min;
  t[index].sum = t[index << 1].sum + t[index << 1 | 1].sum;
}
void build(int l, int r, int index) {
  t[index].c = -1;
  t[index].len = r - l + 1;
  if (l == r) return;
  build(l, ((l + r) >> 1), index << 1);
  build(((l + r) >> 1) + 1, r, index << 1 | 1);
}
inline int query(int l, int r, int index, int x) {
  if (l == r) return t[index].min > x ? l : l - 1;
  pushdown(index);
  if (t[index << 1 | 1].max <= x)
    return query(l, ((l + r) >> 1), index << 1, x);
  else
    return query(((l + r) >> 1) + 1, r, index << 1 | 1, x);
}
void cover(int l, int r, int L, int R, int index, int x) {
  if ((L <= l) && (R >= r)) {
    t[index].cover(x);
    return;
  }
  pushdown(index);
  if (L <= ((l + r) >> 1)) cover(l, ((l + r) >> 1), L, R, index << 1, x);
  if (R > ((l + r) >> 1)) cover(((l + r) >> 1) + 1, r, L, R, index << 1 | 1, x);
  pushup(index);
}
long long qsum(int l, int r, int L, int R, int index) {
  if ((L <= l) && (R >= r)) return t[index].sum;
  pushdown(index);
  long long ans = 0;
  if (L <= ((l + r) >> 1)) ans += qsum(l, ((l + r) >> 1), L, R, index << 1);
  if (R > ((l + r) >> 1))
    ans += qsum(((l + r) >> 1) + 1, r, L, R, index << 1 | 1);
  return ans;
}
inline bool cmp(ele k1, ele k2) { return k1.a < k2.a; }
void modify(int b, int c) {
  int x = b, y = query(1, q, 1, c);
  if (y + 1 <= x) cover(1, q, y + 1, x, 1, c);
}
int main() {
  n = read();
  p = read();
  q = read();
  r = read();
  for (int i = 1; i <= n; i++)
    e[i].a = read(), e[i].b = read(), e[i].c = read();
  sort(e + 1, e + 1 + n, cmp);
  build(1, q, 1);
  for (int i = n; i; i--)
    Q[i] = max(Q[i + 1], e[i].b), R[i] = max(R[i + 1], e[i].c);
  k = 1;
  for (int i = 1; i <= p; i++) {
    while ((k <= n) && (e[k].a < i)) modify(e[k].b, e[k].c), k++;
    int tmp1 = Q[k] + 1, tmp2 = query(1, q, 1, R[k]);
    if (tmp1 <= tmp2) {
      ans += 1LL * (tmp2 - tmp1 + 1) * r - qsum(1, q, tmp1, tmp2, 1);
      ans += 1LL * (r - R[k]) * (q - tmp2);
    } else
      ans += 1LL * (r - R[k]) * (q - tmp1 + 1);
  }
  printf("%I64d", ans);
}
