import std.algorithm, std.array, std.conv, std.range, std.stdio, std.typecons;

immutable Nmax = 1000;

alias Vert = size_t;
alias Edge = Tuple!(Vert, Vert);
alias Face = Tuple!(Vert, Vert, Vert);

class ASC {
	Vert[Vert] nv;		// normalized vertex

	// id := edge_id[ tuple(x, y) ], edge := edges[id];
	// then edge.v1 = x, edge.v2 = y.
	size_t[Edge] edge_id;
	Edge[] edges;
	
	// id := face_id[ tuple(x, y, z) ], face := faces[id];
	// then face.v1 = x, face.v2 = y, face.v3 = z;
	size_t[Face] face_id;
	Face[] faces;
	
	UnionFind uf;			// connectivity
	F_2Vector[] d2, d1;		// homology
	size_t[] least_nonzero_index2, least_nonzero_index1;
	Link[] links;			// links
	
	this () {
		uf = new UnionFind(Nmax);
	}
	
	void add_face(Vert v1, Vert v2, Vert v3) {
		Vert[] added_verts;
		Edge[] added_edges;
		Face[] added_faces;
		
		// start adding
		if (v1 !in nv)
			nv[v1] = nv.length,
			added_verts ~= nv[v1];
		if (v2 !in nv)
			nv[v2] = nv.length,
			added_verts ~= nv[v2];
		if (v3 !in nv)
			nv[v3] = nv.length,
			added_verts ~= nv[v3];
		assert(nv.length <= Nmax);
		
		// normalize
		v1 = nv[v1], v2 = nv[v2], v3 = nv[v3];
		auto _vl = [v1, v2, v3].sort.array;
		v1 = _vl[0], v2 = _vl[1], v3 = _vl[2];
		assert (v1 < v2 && v2 < v3);
		
		if (Edge(v1, v2) !in edge_id)
			edge_id[Edge(v1, v2)] = edges.length,
			edges ~= Edge(v1, v2),
			added_edges ~= Edge(v1, v2);
			
		if (Edge(v1, v3) !in edge_id)
			edge_id[Edge(v1, v3)] = edges.length,
			edges ~= Edge(v1, v3),
			added_edges ~= Edge(v1, v3);
			
		if (Edge(v2, v3) !in edge_id)
			edge_id[Edge(v2, v3)] = edges.length,
			edges ~= Edge(v2, v3),
			added_edges ~= Edge(v2, v3);
			
		if (Face(v1, v2, v3) !in face_id)
			face_id[Face(v1, v2, v3)] = faces.length,
			faces ~= Face(v1, v2, v3),
			added_faces ~= Face(v1, v2, v3);
		
		// calculate connectivity
		foreach (face; added_faces) {
			uf.unite(face[0], face[1], face[2]);
		}
		
		// calculate homology
		foreach (edge; added_edges) {
			F_2Vector vector;
			vector.set_entry(edge[0], true);
			vector.set_entry(edge[1], true);
			add_row(d1, least_nonzero_index1, vector);
		}
		foreach (face; added_faces) {
			F_2Vector vector;
			vector.set_entry(edge_id[Edge(face[0], face[1])], true);
			vector.set_entry(edge_id[Edge(face[0], face[2])], true);
			vector.set_entry(edge_id[Edge(face[1], face[2])], true);
			add_row(d2, least_nonzero_index2, vector);
		}
		
		// calculate links
		links.length += added_verts.length;
		foreach (vert; added_verts) {
			auto link = new Link(vert);
			links[vert] = link;
		}
		foreach (face; added_faces) {
			links[face[0]].add_edge(Edge(face[1], face[2]));
			links[face[1]].add_edge(Edge(face[0], face[2]));
			links[face[2]].add_edge(Edge(face[0], face[1]));
		}
	}
	
	// connectivity
	bool is_connected() {
		return uf.size(faces[0][0]) == nv.length;
	}
	
	// homology
	size_t dim_H_1() {
		auto dim_im_d2 = d2.length;
		auto dim_im_d1 = d1.length;
		auto dim_ker_d1 = edges.length - dim_im_d1;
		assert(dim_ker_d1 >= dim_im_d2);
		return dim_ker_d1 - dim_im_d2;
	}
	
	// keeping row echolon form
	void add_row(ref F_2Vector[] matrix, ref size_t[] lni, F_2Vector vector) {
		size_t iv;
		least_nonzero_index(vector, iv);	// least nonzero index of vector
		foreach (j, row; matrix) {
			if (iv > vector_size) return;	// vector is linearly dependent
			auto ir = lni[j];
			if (iv < ir) {	// insert v
				matrix = matrix[0 .. j] ~ [vector] ~ matrix[j .. $];
				lni = lni[0 .. j] ~ [iv] ~ lni[j .. $];
				return;
			}
			else if (iv == ir) {
				vector[] ^= row[];	// sweep
				least_nonzero_index(vector, iv);
			}
		}
		if (iv < vector_size) matrix ~= vector, lni ~= iv;
	}
	
	// link {i} 
	class Link {
		bool[Vert] vert_set;
		Vert of_vert;
		UnionFind lkuf;
		
		this (Vert vert) {
			this.of_vert = vert;
			lkuf = new UnionFind(Nmax);	
		}
		
		void add_edge(Edge edge) {
			vert_set[edge[0]] = true;
			vert_set[edge[1]] = true;
			lkuf.unite(edge[0], edge[1]);
		}
		
		bool is_connected() {
			return lkuf.size(vert_set.keys[0]) == vert_set.length;
		}
	}
}

void main() {
	auto MN = readln.split.to!(size_t[]);
	auto N = MN[0], M = MN[1];
	size_t[][] face_list;
	foreach (m; 0 .. M) {
		face_list ~= readln.split.to!(size_t[]);
	}
	
	auto asc = new ASC;
	foreach (i, face; face_list) {
		asc.add_face(face[0], face[1], face[2]);
		if (!asc.is_connected)
			writeln("CO");
		else if (asc.dim_H_1 != 0)
			writeln("H1");
		else if (!asc.links.all!(link => link.is_connected))
			writeln("LK");
		else
			writeln("CM");
	}
	
	/+foreach (i, link; asc.links) {
		writeln(i+1);
		foreach (vert; link.vert_set.keys) {
			writefln("    (%d->%d) ", vert+1, link.lkuf.root(vert)+1);
		}
	}+/
}

/***************************************************************************
****************************************************************************/

alias F_2Vector = size_t[50];		// 50 * 64 > 300
immutable ulong_size = 8 * (size_t.sizeof);
immutable vector_size = 3000;

void set_entry(ref F_2Vector vector, size_t n_th, bool val) {
	if (val)
		vector[n_th / ulong_size] |= 1UL << n_th % ulong_size;
	else
		vector[n_th / ulong_size] &= ~0UL - (1UL << (n_th % ulong_size));
}

bool get_entry(F_2Vector vector, size_t n_th) {
	return (vector[n_th / ulong_size] & (1UL << n_th % ulong_size)) != 0;
}

bool is_zero(F_2Vector vector) {
	foreach (e; vector) if (e != 0) return false;
	return true;
}

void least_nonzero_index(F_2Vector vector, ref size_t i) {
	// determine iv
	foreach (index, entry; vector[i/ulong_size .. $]) {
		if (entry != 0)
			foreach (r; 0 .. ulong_size)
				if (vector.get_entry(index*ulong_size + r)) {
					i = index*ulong_size + r;
					return;
				}
	}
	i = vector_size + 1;
}

/+
// to row echolon form
F_2Vector[] reform(ref F_2Vector[] matrix) {
	size_t j;
	foreach (i; 0 .. matrix.length) {
		while (j < vector_size) {
			// find nonzero entry
			foreach (i2; i .. matrix.length) {
				if (get_entry(matrix[i2], j)) {
					swap(matrix[i2], matrix[i]);
					break;
				}
			}
		
			// all zero
			if (!get_entry(matrix[i], matrix[i2])) {
				++j;
			}
			else {
				// sweeping
				foreach (i2; i+1 .. matrix.length) {
				if (get_entry(matrix[i2], j)) matrix[i2] ^= matrix[i];
				++j;
				break;
			}
		}
	}
}
+/

// Union-tree of {0, 1, ..., num-1}
class UnionFind {
	size_t num;
	private size_t[] parent;
	private size_t[] rank;
	private size_t[] size_;
	
	this (size_t num) {
	    this.num = num;
	    parent.length = num;
	    foreach (n; 0 .. num) parent[n] = n;
	    rank.length = num;
	    size_.length = num;
	}
	
	size_t root(size_t n) {
	    assert(n < num);
	    if (parent[n] == n) return n;
	    else return parent[n] = root(parent[n]);    // recursively set the root
	}
	
	bool is_same(size_t n, size_t m) {
		assert(n < num && m < num);
		return root(n) == root(m);
	}
	
	// false if already united
	bool unite(size_t n, size_t[] mlist...) {
		assert(n < num);
		bool result;
		foreach (m; mlist) {
			assert(m < num);
			auto rn = root(n), rm = root(m);
			if (rn == rm) continue;
			// swap if necessary to force rank[rm] <= rank[rn]
			if (rank[rn] < rank[rm]) {
				auto tmp = rm;
				rm = rn;
				rn = tmp;
			}
			parent[rm] = rn;
			if (rank[rn] == rank[rm]) ++rank[rn];
			size_[rn] += size_[rm] + 1;
			result = true;
		}
		return result;
	}
	
	size_t size(size_t n) {
		return size_[root(n)]+1;
	}
	
	size_t size() {
		size_t result;
		foreach (i; 0 .. num)
			if (root(i) == i) result += 1;
		return result;
	}
}