package arupsClassFinalTeam;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
/*
2
4 3
nice 2 1 3
naughty 2 2 4
nice 1 1
4 3
nice 2 1 3
nice 2 2 4
nice 1 1
 */
public class ElfDavidSolBS {

	public static void main(String[] args) {
		Scanner fs=new Scanner(System.in);
		int T=fs.nextInt();
		for (int tt=0; tt<T; tt++) {
			int nToys=fs.nextInt(), nKids=fs.nextInt();
			Kid[] kids=new Kid[nKids];
			for (int i=0; i<nKids; i++) {
				boolean nice=fs.next().equals("nice");
				int nFlipped=fs.nextInt();
				boolean[] legal=new boolean[nToys];
				if (!nice) Arrays.fill(legal, true);
				for (int j=0; j<nFlipped; j++) {
					int ind=fs.nextInt()-1;
					if (legal[ind]==nice) throw null;
					legal[ind]=nice;
				}
				kids[i]=new Kid(legal);
			}
			int minAns=0, maxAns=nKids;
			while (minAns!=maxAns) {
				int mid=(minAns+maxAns)/2;
				if (check(nToys, nKids, mid, kids))
					maxAns=mid;
				else
					minAns=mid+1;
			}
			System.out.println(minAns);
		}
	}
	
	static boolean check(int nToys, int nKids, int ans, Kid[] kids) {
		//nodes: kids, toys, (s/t)
		Dinic d=new Dinic(nKids+nToys);
		for (int i=0; i<nKids; i++) d.add(d.s, i, 1, 0);
		for (int i=0; i<nToys; i++) d.add(nKids+i, d.t, ans, 0);
		for (int k=0; k<nKids; k++)
			for (int i=0; i<nToys; i++)
				if (kids[k].legalMatches[i])
					d.add(k, nKids+i, 1, 0);
		int flow=d.flow();
		return flow==nKids;
	}

	static class Kid {
		boolean[] legalMatches;
		public Kid(boolean[] legalMatches) {
			this.legalMatches=legalMatches;
		}
	}
	
	static class Dinic {
		static class Edge {  int v1, v2, cap, flow; Edge rev;
			Edge(int V1, int V2, int Cap, int Flow) { v1 = V1; v2 = V2; cap = Cap; flow = Flow; }
		}

		ArrayDeque<Integer> q;  ArrayList<Edge>[] adj;
		int n, s, t, mS, mT, oo = (int)1E9;
		boolean[] blocked;  int[] dist;
		public Dinic (int N) {
			n = N; s = n++; t = n++; mS = n++; mT = n++; blocked = new boolean[n];
			dist = new int[n];  q = new ArrayDeque<Integer>();
			adj = new ArrayList[n];  for(int i = 0; i < n; ++i)  adj[i] = new ArrayList<Edge>();
		}
		// Specifying flow can represent minimum flow for circulation.
		Edge add(int v1, int v2, int cap, int flow) {
			Edge e = new Edge(v1, v2, cap, flow);  Edge rev = new Edge(v2, v1, 0, 0);
			adj[v1].add(rev.rev = e);  adj[v2].add(e.rev = rev);
			return e;
		}

		boolean bfs() {
			q.clear();  Arrays.fill(dist, -1);  dist[t] = 0;  q.add(t);

			while(!q.isEmpty()) {
				int node = q.poll();
				if(node == s)   return true;
				for(Edge e : adj[node]) {
					if(e.rev.cap > e.rev.flow && dist[e.v2] == -1) {
						dist[e.v2] = dist[node] + 1;  q.add(e.v2);
					}
				}
			}
			return dist[s] != -1;
		}

		int dfs(int pos, int min) {
			if(pos == t)  return min;
			int flow = 0;
			for(Edge e : adj[pos]) {
				int cur = 0;
				if(!blocked[e.v2] && dist[e.v2] == dist[pos]-1 && e.cap - e.flow > 0) {
					cur = dfs(e.v2, Math.min(min-flow, e.cap - e.flow));
					e.flow += cur;  e.rev.flow = -e.flow;  flow += cur;
				}
				if(flow == min)  return flow;
			}
			blocked[pos] = flow != min;
			return flow;
		}
		int flow() {
			clear();  int ret = 0;
			while(bfs()) {  Arrays.fill(blocked, false);  ret += dfs(s, oo);  }
			return ret;
		}
		void clear() {  for(ArrayList<Edge> edges : adj)  for(Edge e : edges)  e.flow = 0;  }
	}
}
