1. 

/**
* FWP, Ausgewählte Probleme aus dem ACM Programming Contest, SS2010
* Problem: 825 Walking on the Safe Side
* Link: http://uva.onlinejudge.org/external/8/825.pdf
*
* @author Barny Porcio
* @version 1.0, 06/27/2010
*
* Status : Accepted
* Runtime: 0.100
*/

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.util.TreeSet;

public class WalkingontheSafeSide {
static int W;
static int N;
static int shortest;
static int counter;
static TreeSet<Integer>[] block;
public static void findway(int zeile,int spa){
int spalte = spa;
Integer nexteshinternis = block[zeile].ceiling(spa);
if (zeile == W-1){
if (nexteshinternis == null){
++counter;
}
return;
}
if (nexteshinternis == null)
nexteshinternis = N;

while (spalte <= N-1 && spalte != nexteshinternis){
findway(zeile+1,spalte);
++spalte;
}

}


/**
* @param args
* @throws IOException
*/
@SuppressWarnings("unchecked")
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
for (int cases = Integer.parseInt(br.readLine()); cases > 0; --cases){
br.readLine();
shortest = Integer.MAX_VALUE;
StringTokenizer st = new StringTokenizer(br.readLine());
W = Integer.parseInt(st.nextToken());
N = Integer.parseInt(st.nextToken());
counter = 0;
shortest = W+N-2;
//block = new boolean[W][N];
block = new TreeSet[W];
for (int i = 0; i < W; ++i){
block[i] = new TreeSet<Integer>();
st = new StringTokenizer(br.readLine());

int zeile = Integer.parseInt(st.nextToken());
while (st.hasMoreTokens())
block[zeile-1].add(Integer.valueOf(st.nextToken())-1);
}
findway(0, 0);
System.out.println(counter);
if (cases !=1)
System.out.println();

}

}

}