#include <fstream>
#include <algorithm>
using namespace std;
ifstream fin ("cutii.in");
ofstream fout ("cutii.out");
int N ; int T;
class Boxes {
static const int NMAX = 3505;
static const int TMAX = 102;
private:
short int AIB[NMAX][NMAX];
inline int bit(int X) { return X & ((X - 1) ^ X); }
public:
class Dimensions {
public:
int x; int y; int z;
Dimensions(){ this -> x = 0 ; this -> y = 0 ; this -> z = 0; }
bool operator < (const Dimensions D) const {
if(this -> x == D.x && this -> y == D.y) return this -> z < D.z;
if(this -> x == D.x) return this -> y < D.y;
return this -> x < D.x;
}
}V[NMAX];
short int query(int X, int Y) {
short int maximum_value = 0;
for(int i = X; i ; i -= bit(i))
for(int j = Y; j ; j -= bit(j))
maximum_value = max(AIB[i][j], maximum_value);
return maximum_value;
}
void update(int X, int Y,short int Value) {
for(int i = X; i <= N; i += bit(i))
for(int j = Y; j <= N; j += bit(j))
AIB[i][j] = max(AIB[i][j], Value);
}
void erase_bit(int X, int Y) {
for(int i = X ; i <= N; i += bit(i))
for(int j = Y; j <= N; j += bit(j))
AIB[i][j] = 0;
}
} Box;
int main() {
fin >> N >> T;
for(int i = 1; i <= T; ++i) {
for(int j = 1; j <= N; ++j) {
fin >> Box.V[j].x >> Box.V[j].y >> Box.V[j].z;
}
sort(&Box.V[1], &Box.V[N]);
int Solution = 0;
for(int j = 1; j <= N; ++j) {
short int Value = Box.query(Box.V[j].y, Box.V[j].z) + 1;
Box.update(Box.V[j].y, Box.V[j].z, Value);
if(Solution < Value)
Solution = Value;
}
for(int j = 1 ; j <= N; ++j)
Box.erase_bit(Box.V[j].x, Box.V[j].z);
fout << Solution << '\n';
}
return 0;
}