#include <bits/stdc++.h>
using namespace std;
#pragma GCC target("avx2")
#pragma GCC optimization("O3")
#pragma GCC optimization("unroll-loops")
const int N = 2e3 + 5;
const int mod = 1e9 + 7;
int n, k, L, dsa[N], nxt[N], f[N], cnt[N];
vector<int> vecY[N], vecX[N];
set<int> col[N];
int lazy[4 * N], len[4 * N], sum[4 * N], last[4 * N];
vector<int> coorX, coorY;
struct Point {
  int x, y, c;
} p[N];
void init(int v, int l, int r) {
  len[v] = coorX[r] - coorX[l - 1];
  if (l < r) {
    int mid = (l + r) / 2;
    init(v * 2, l, mid);
    init(v * 2 + 1, mid + 1, r);
  }
}
void push(int v, int l, int r) {
  if (lazy[v] != -1) {
    last[v] = lazy[v];
    sum[v] = 1ll * len[v] * (L - coorX[lazy[v]]) % mod;
    if (l < r) {
      lazy[v * 2] = lazy[v];
      lazy[v * 2 + 1] = lazy[v];
    }
    lazy[v] = -1;
  }
}
void update(int v, int l, int r, int L, int R, int qv) {
  push(v, l, r);
  if (L > r || R < l) return;
  if (L <= l && r <= R) {
    lazy[v] = qv;
    push(v, l, r);
    return;
  }
  int mid = (l + r) / 2;
  update(v * 2, l, mid, L, R, qv);
  update(v * 2 + 1, mid + 1, r, L, R, qv);
  sum[v] = (sum[v * 2] + sum[v * 2 + 1]) % mod;
  last[v] = last[v * 2 + 1];
}
int fin(int v, int l, int r, int qv) {
  push(v, l, r);
  if (last[v] <= qv) return -1;
  if (l == r) return l;
  int mid = (l + r) / 2;
  int ans = fin(v * 2, l, mid, qv);
  if (ans == -1) ans = fin(v * 2 + 1, mid + 1, r, qv);
  return ans;
}
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(nullptr);
  cin >> n >> k >> L;
  coorX.push_back(-1), coorX.push_back(L);
  coorY.push_back(-1), coorY.push_back(L);
  for (int i = 1; i <= n; i++) {
    cin >> p[i].x >> p[i].y >> p[i].c;
    coorX.push_back(p[i].x);
    coorY.push_back(p[i].y);
  }
  sort(coorX.begin(), coorX.end());
  coorX.erase(unique(coorX.begin(), coorX.end()), coorX.end());
  sort(coorY.begin(), coorY.end());
  coorY.erase(unique(coorY.begin(), coorY.end()), coorY.end());
  for (int i = 1; i <= n; i++) {
    int id = lower_bound(coorY.begin(), coorY.end(), p[i].y) - coorY.begin();
    vecY[id].push_back(i);
    id = lower_bound(coorX.begin(), coorX.end(), p[i].x) - coorX.begin();
    vecX[id].push_back(i);
  }
  int res = 0;
  for (int up = coorY.size() - 2; up >= 1; up--) {
    for (int i = 1; i <= k; i++) {
      col[i].clear();
      cnt[i] = 0;
    }
    memset(lazy, -1, sizeof lazy);
    for (int i = up; i >= 1; i--) {
      for (auto& id : vecY[i]) {
        int x = p[id].x;
        int c = p[id].c;
        auto it = col[c].lower_bound(x);
        if (it == col[c].end())
          nxt[id] = L;
        else
          nxt[id] = *it;
        it = col[c].upper_bound(x);
        if (it == col[c].begin())
          dsa[id] = -1;
        else
          dsa[id] = *(--it);
      }
      for (auto& id : vecY[i]) col[p[id].c].insert(p[id].x);
    }
    int j = 1;
    int cur = 0;
    init(1, 1, coorX.size() - 2);
    for (int i = 1; i <= coorX.size() - 2; i++) {
      while (j <= coorX.size() - 2) {
        for (auto& id : vecX[j]) {
          if (p[id].y <= coorY[up]) {
            if (cnt[p[id].c] == 0) cur++;
            cnt[p[id].c]++;
          }
        }
        if (cur == k) {
          for (auto& id : vecX[j]) {
            if (p[id].y <= coorY[up]) {
              cnt[p[id].c]--;
              if (cnt[p[id].c] == 0) cur--;
            }
          }
          break;
        }
        j++;
      }
      for (auto& id : vecX[i]) {
        if (p[id].y <= coorY[up]) {
          cnt[p[id].c]--;
          if (cnt[p[id].c] == 0) cur--;
        }
      }
      update(1, 1, coorX.size() - 2, i, i, j);
    }
    for (int down = 1; down <= up; down++) {
      push(1, 1, coorX.size() - 2);
      int add = 1ll * sum[1] * (coorY[up + 1] - coorY[up]) % mod *
                (coorY[down] - coorY[down - 1]) % mod;
      res = (res + add) % mod;
      for (auto& i : vecY[down]) {
        int l =
            lower_bound(coorX.begin(), coorX.end(), dsa[i]) - coorX.begin() + 1;
        int v = lower_bound(coorX.begin(), coorX.end(), p[i].x) - coorX.begin();
        int val =
            lower_bound(coorX.begin(), coorX.end(), nxt[i]) - coorX.begin();
        int r = fin(1, 1, coorX.size() - 2, val);
        if (r == -1) r = coorX.size() - 1;
        r--;
        r = min(r, v);
        if (l <= r) update(1, 1, coorX.size() - 2, l, r, val);
      }
    }
  }
  cout << res;
}
