#include <bits/stdc++.h>

using namespace std;

#define ll long long

//#define TEST

struct LazySegmentTree {
private:
	int n;
	vector<ll> node, lazy;

public:
	LazySegmentTree(vector<ll> v) {
		int sz = (int)v.size();
		n = 1; while (n < sz) n *= 2;
		node.resize(2 * n - 1);
		lazy.resize(2 * n - 1, 0);

		for (int i = 0; i < sz; i++) node[i + n - 1] = v[i];
		for (int i = n - 2; i >= 0; i--) node[i] = node[i * 2 + 1] + node[i * 2 + 2];
	}

	void eval(int k, int l, int r) {
		if (lazy[k] != 0) {
			node[k] += lazy[k];
			if (r - l > 1) {
				lazy[2 * k + 1] += lazy[k] / 2;
				lazy[2 * k + 2] += lazy[k] / 2;
			}
			lazy[k] = 0;
		}
	}

	void add(int a, int b, ll x, int k = 0, int l = 0, int r = -1) {
		if (r < 0) r = n;
		eval(k, l, r);
		if (b <= l || r <= a) return;
		if (a <= l && r <= b) {
			lazy[k] += (r - l) * x;
			eval(k, l, r);
		}
		else {
			add(a, b, x, 2 * k + 1, l, (l + r) / 2);
			add(a, b, x, 2 * k + 2, (l + r) / 2, r);
			node[k] = node[2 * k + 1] + node[2 * k + 2];
		}
	}

	ll getsum(int a, int b, int k = 0, int l = 0, int r = -1) {
		if (r < 0) r = n;
		eval(k, l, r);
		if (b <= l || r <= a) return 0;
		if (a <= l && r <= b) return node[k];
		ll vl = getsum(a, b, 2 * k + 1, l, (l + r) / 2);
		ll vr = getsum(a, b, 2 * k + 2, (l + r) / 2, r);
		return vl + vr;
	}
};


struct TVprog {
	pair<int, int> st; // 開始時刻と終了時刻
	int c; // チャンネル
};

signed main() {
	int n, c;
	cin >> n >> c;

	int tmax = 0; // tiの最大値

	vector<TVprog> p(n);
	for (int i = 0; i < n; ++i) {
		cin >> p[i].st.first >> p[i].st.second >> p[i].c;
		tmax = max(tmax, p[i].st.second);
	}

	/* 番組をチャンネルごとにわけ、まとめられる番組はまとめる */
	vector<vector<TVprog>> pc(c + 1);
	for (int i = 0; i < n; ++i) // チャンネルごとにわける
		pc[p[i].c].push_back(p[i]);
	for (int i = 0; i <= c; ++i) { // 各チャンネル内でソート
		sort(
			pc[i].begin(),
			pc[i].end(),
			[](TVprog a, TVprog b) {
				return a.st.second < b.st.second;
			}
		);
	}
	vector<TVprog> new_p;
	for (int i = 0; i <= c; ++i) {
		if (pc[i].size() == 0) continue;
		if (pc[i].size() == 1) {
			new_p.push_back(pc[i][0]);
			continue;
		}
		int si = -1;
		int ti = -1;
		for (int j = 0; j < pc[i].size(); ++j) {
			if (si == -1 && ti == -1)
				si = pc[i][j].st.first;
			ti = pc[i][j].st.second;
			// 次とまとめられないならば
			if (j < pc[i].size() - 1 && ti != pc[i][j + 1].st.first) {
				TVprog t;
				t.st = make_pair(si, ti);
				t.c = i;
				new_p.push_back(t);
				si = -1;
				ti = -1;
				continue;
			}
		}
		TVprog t;
		t.st = make_pair(si, ti);
		t.c = i;
		new_p.push_back(t);
	}
	p = new_p;

	/* 番組を終了時刻の早い順にソート */
	sort(
		p.begin(),
		p.end(),
		[](TVprog a, TVprog b) {
			return a.st.second < b.st.second;
		}
	);

#ifdef TEST // ソートしたpを確認
	cout << "---------sorted TV programs-----------" << endl;
	for (auto pi : p) {
		cout << pi.st.first << " ";
		cout << pi.st.second << " ";
		cout << pi.c << endl;
	}
	cout << endl;
#endif

	/* 各時刻に何台の録画機が必要か遅延セグメント木で管理. */
	vector<ll> dat(tmax + 1, 0);
	LazySegmentTree rsq(dat);
	for (auto pi : p) {
		rsq.add(pi.st.first, pi.st.second + 1, 1);
	}

#ifdef TEST
	cout << "---------number of recorders----------" << endl;
	for (int i = 0; i <= tmax; ++i)
		cout << rsq.getsum(i, i + 1) << endl;
#endif

	/* 上記で求めたデータの最大値が答え. */
	ll ans = 0;
	for (int i = 0; i <= tmax; ++i)
		ans = max(ans, rsq.getsum(i, i + 1));

#ifdef TEST
	cout << "---------ans--------------------------"  << endl;
#endif
	cout << ans << endl;

	return 0;
}

Measured memory_bytes: 10164