//interesant sa folosesti aib pentru maxim, doar pentru
//ca ni se cere maxim pe un interval de genul (1, 1) -> (n, m)
//#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
using namespace std;
//dp[i] = nr. max. de cutii ce pot fi alese cu cutia i fiind ultima
//dp[i] = 1 + max(dp[j]), cu dimensiunile cutii lui j mai mari ca ale lui i
const int NMAX = 3500;
struct cub
{
int x, y, z;
} v[NMAX + 3];
bool cmp(cub a, cub b)
{
return a.x < b.x;
}
int n;
int aib[NMAX + 1][NMAX + 1];
void update(int i, int j, int val)
{
for (; i <= n; i += i & -i)
for (; j <= n; j += j & -j)
aib[i][j] += val;
}
int query(int a, int b)
{
int ans = 0;
for (; a >= 1; a -= a & -a)
for (; b >= 1; b -= b & -b)
ans = max(ans, aib[a][b]);
return ans;
}
int aux[NMAX + 1];
int main()
{
ifstream cin("cutii.in");
ofstream cout("cutii.out");
int t, i, j;
cin >> n >> t;
while (t--)
{
int ans = 0;
for (i = 1; i <= n; i++)
{
cin >> v[i].x >> v[i].y >> v[i].z;
}
sort(v + 1, v + n + 1, cmp);
int last = 1;
for (i = 1; i <= n; i++)
{
if (v[i].x != v[last].x)
{
for (j = last; j < i; j++)
{
aux[j] = 1 + query(v[j].y - 1, v[j].z - 1);
ans = max(ans, aux[j]);
}
for (j = last; j < i; j++)
update(v[j].y, v[j].z, aux[j]);
last = i;
}
}
for (j = last; j < i; j++)
{
aux[j] = 1 + query(v[j].y - 1, v[j].z - 1);
ans = max(ans, aux[j]);
}
for (j = last; j < i; j++)
update(v[j].y, v[j].z, aux[j]);
cout << ans << "\n";
for (i = 1; i <= n; i++)
update(v[i].y, v[i].z, -aux[i]);
}
}