#include <bits/stdc++.h>   using namespace std;   const int mod = 1e9 + 7;   struct node {     int x, y, c;   } s[2005], tmp[2005];   int n, k, l, cx, cy;   int lx[2005], ly[2005], bk[2005];   multiset<int> t[2005];   namespace Tree {   int mn[8005], mx[8005], sum[8005], lzy[8005];   inline void pushtag(int p, int l, int r, int val) {     mx[p] = mn[p] = lzy[p] = val;     sum[p] = 1ll * (ly[r + 1] - ly[l]) * val % mod;   }   inline void down(int p, int l, int mid, int r) {     pushtag(p << 1, l, mid, lzy[p]);     pushtag(p << 1 | 1, mid + 1, r, lzy[p]);     lzy[p] = -1;   }   void insert(int p, int id, int val, int l, int r) {     if (l == r)       return mx[p] = mn[p] = val,              sum[p] = 1ll * (ly[id + 1] - ly[id]) * val % mod, void();     const int mid = l + r >> 1;     if (id <= mid)       insert(p << 1, id, val, l, mid);     else       insert(p << 1 | 1, id, val, mid + 1, r);     mn[p] = min(mn[p << 1], mn[p << 1 | 1]);     mx[p] = max(mx[p << 1], mx[p << 1 | 1]);     sum[p] = (sum[p << 1] + sum[p << 1 | 1]) % mod;   }   void qmin(int p, int val, int l, int r, int L, int R) {     if (L >= l && R <= r) {       if (mx[p] <= val)         return;       else if (mn[p] >= val)         pushtag(p, L, R, val);       else {         const int mid = L + R >> 1;         if (~lzy[p]) down(p, L, mid, R);         qmin(p << 1, val, l, r, L, mid);         qmin(p << 1 | 1, val, l, r, mid + 1, R);         mn[p] = min(mn[p << 1], mn[p << 1 | 1]);         mx[p] = max(mx[p << 1], mx[p << 1 | 1]);         sum[p] = (sum[p << 1] + sum[p << 1 | 1]) % mod;       }       return;     }     const int mid = L + R >> 1;     if (~lzy[p]) down(p, L, mid, R);     if (l <= mid) qmin(p << 1, val, l, r, L, mid);     if (r > mid) qmin(p << 1 | 1, val, l, r, mid + 1, R);     mn[p] = min(mn[p << 1], mn[p << 1 | 1]);     mx[p] = max(mx[p << 1], mx[p << 1 | 1]);     sum[p] = (sum[p << 1] + sum[p << 1 | 1]) % mod;   }   }  // namespace Tree   int main() {     scanf( %d%d%d , &n, &k, &l);     lx[++cx] = 0;     ly[++cy] = 0;     lx[++cx] = l + 1;     ly[++cy] = l + 1;     int ans = 0;     for (int i = 1; i <= n; ++i)       scanf( %d%d%d , &s[i].x, &s[i].y, &s[i].c), lx[++cx] = ++s[i].x,                                                   ly[++cy] = ++s[i].y;     sort(lx + 1, lx + cx + 1);     cx = unique(lx + 1, lx + cx + 1) - lx - 1;     sort(ly + 1, ly + cy + 1);     cy = unique(ly + 1, ly + cy + 1) - ly - 1;     for (int i = 1; i <= n; ++i)       s[i].x = lower_bound(lx + 1, lx + cx + 1, s[i].x) - lx,       s[i].y = lower_bound(ly + 1, ly + cy + 1, s[i].y) - ly, tmp[i] = s[i];     sort(s + 1, s + n + 1,          [](const node &a, const node &b) { return a.x < b.x; });     sort(tmp + 1, tmp + n + 1,          [](const node &a, const node &b) { return a.y < b.y; });     for (int u = 1; u < cx; ++u) {       memset(bk, 0, sizeof(bk));       memset(Tree::lzy, -1, sizeof(Tree::lzy));       for (int i = 1, j = 1, p = 1, cnt = 0; i < cy; ++i) {         while (j <= n && tmp[j].y <= i) {           if (tmp[j].x <= u)             ++j;           else {             if (!bk[tmp[j].c]) ++cnt;             ++bk[tmp[j++].c];           }         }         while (cnt == k) {           if (tmp[p].x <= u)             ++p;           else {             --bk[tmp[p].c];             if (!bk[tmp[p++].c]) --cnt;           }         }         Tree::insert(1, i, ly[tmp[p - 1].y], 1, cy - 1);       }       for (int i = 1; i <= k; ++i) t[i].clear();       for (int i = 1; i <= n; ++i)         if (s[i].x > u) t[s[i].c].insert(s[i].y);       for (int d = cx - 1, i = n; d > u; --d) {         (ans += 1ll * (lx[d + 1] - lx[d]) * (lx[u + 1] - lx[u]) % mod *                 Tree::sum[1] % mod) %= mod;         while (i && s[i].x >= d) {           auto it = t[s[i].c].find(s[i].y);           int pre = it == t[s[i].c].begin() ? 0 : *prev(it);           int nxt = next(it) == t[s[i].c].end() ? cy : *next(it);           t[s[i].c].erase(it);           if (s[i].y < nxt) Tree::qmin(1, ly[pre], s[i].y, nxt - 1, 1, cy - 1);           --i;         }       }     }     return printf( %d n , ans), 0;   }   