#include <bits/stdc++.h> 

using namespace std;

#define fcout(d) cout << fixed << setprecision(d)
#define rep(i,n) for(int (i) = 0; (i) < (n); ++(i))
#define rep1(i,n) for(int (i) = 1; (i) <= (n); ++(i))
#define repU(i,bottom,ceiling) for(int (i) = (bottom); (i) <= (ceiling); ++(i))
#define repD(i,ceiling,bottom) for(int (i) = (ceiling); (i) >= (bottom); --(i))
#define pub push_back
#define pob pop_back
#define prf printf
#define scf scanf
#define mkp make_pair
#define fir first
#define sec second
#define clr(a) memset((a),0,sizeof(a))
#define all(a)  begin((a)),end((a))

typedef long long ll;
typedef unsigned long long ull;
typedef double db;

const vector<pair<int,int>> DIR = { {1,0},{0,1},{-1,0},{0,-1},{1,1},{-1,1},{-1,-1},{1,-1} };
const int INF = -1 + (1<<30);
const int MOD = (int)1e9 + 7;

template<typename T> inline T gcd(T a,T b){ if(a % b){ return gcd(b,a % b); }else{ return b; } }

template<typename T> inline T lcm(T a,T b){ return a / gcd(a,b) * b; }

inline long long Pow(const long long n,long long m,const int mod = MOD){
	long long res = 1,pow = n;
	while(m) {
		if(m & 1) res = (res * pow) % mod;
		pow = (pow * pow) % mod;
		m >>= 1;
	}
	return res;
}

inline vector<long long> Frac(const int range,const int mod = MOD){
	vector<long long> frac;
	frac.push_back(1);
	for(int i = 1; i <= range; ++i) frac.push_back((long long)frac.back() * i % mod);
	return frac;
}

inline long long Comb(const int n,const int m,const int mod = MOD){
	if(n < m || m < 0) return 0;
	vector<long long> frac(Frac(n,mod));
	long long rev = Pow((long long)frac[m] * frac[n-m] % mod,mod-2,mod);
	return rev * frac[n] % mod;
}

template<typename T> inline bool v_find(const vector<T> v,const T obj){
	auto itr = find(v.begin(), v.end(), obj);
	size_t index = distance(v.begin(),itr);
	if (index != v.size()) { return true; }
	return false; 
}

template<typename T> inline bool v_erase(vector<T> &v,const T obj){
	auto itr = find(v.begin(), v.end(), obj);
	size_t index = distance(v.begin(),itr);
	if (index != v.size()) {
		v.erase(itr);
		return true;
	}
	return false;	
}

template<class T,class U> inline auto LB(const T v,const U in){ return lower_bound(v.begin(),v.end(),in); }

template<class T,class U> inline auto UB(const T v,const U in){ return upper_bound(v.begin(),v.end(),in); }

inline unsigned long long next_subset(unsigned long long subset){
	unsigned long long tem = subset + (subset & -subset);
	unsigned long long btm = (~tem & subset) / (subset & -subset) >> 1;
	return btm | tem;
}

int N,C;
vector<pair<int,int>> dur[30];

inline void solve(){
	bool is[30][100001]={{}};
	rep(i,30){
		if(dur[i].empty()) continue;
		sort(dur[i].begin(),dur[i].end());
		int now=dur[i][0].fir;
		for(int j=0;j<dur[i].size();++j){
			if(now>=dur[i][j].sec) continue;
			fill(is[i]+max(dur[i][j].fir,now),is[i]+dur[i][j].sec,1);
			now=dur[i][j].sec;
		}
		cout<<endl;
	}
	int ans=1;
	rep1(t,100000){
		int cur=0;
		rep(c,30){
			if(is[c][t]|is[c][t+1]) ++cur;
		}
		ans=max(ans,cur);
	}
	cout<<ans;
	return;
}

inline void input(){
	cin>>N>>C;
	rep(i,N){
		int a,b,c; cin>>a>>b>>c;
		dur[--c].pub({a,b});
	}
	return;
}

int main(){
	cin.tie(0);
	ios::sync_with_stdio(false);
	input();
	solve();
	return 0;
}





Measured memory_bytes: 4480