//首次接触并查集,虽然是最基本的题目,但是不是很会做,
//所以就看明白了并查集(看算法导论)和别人的代码之后,再自己写出来的!
#include "iostream"
using namespace std;
const int maxsize = 30010;
int pa[maxsize];//每一个集合中元素的父节点
int ranks[maxsize];//每一个集合中元素的秩
int num[maxsize];//每一个父节点下的叶子树
void make_set(int x)//首先初始化,每一个元素的父节点都是它自己本身!
{
pa[x] = x;
ranks[x] = 0;
num[x] = 1;
}
int find_set(int x)//查找元素的根节点,采用递归的方法!
{
if (x != pa[x])
pa[x] = find_set(pa[x]);
return pa[x];
}
void union_set(int x, int y)//将两个集合合并为一个集合!并且秩大的作为父节点,如果秩相等的,就随意找一个作为父节点即可!
{
x = find_set(x);
y = find_set(y);
if (x == y) return;//如果两个元素相同的,就不用合并了,直接返回!
if (ranks[x] > ranks[y])
{
pa[y] = x;
num[x] += num[y];
}
else
{
pa[x] = y;
if (ranks[x] == ranks[y])
ranks[y]++;
num[y] += num[x];
}
}
int main()
{
int n, m, i, j, s, x, y, ans;
while (cin >> n >> m )
{
if (n == 0 && m == 0)
break;
if (m == 0)
{
cout << 1 << endl;
continue;
}
for (i = 0; i < n; i++)
make_set(i);
for (i = 0; i < m; i++)
{
cin >> s >> x;
for (j = 1; j < s; j++)
{
cin >> y;
union_set(x, y);
x = y;
}
}
ans = find_set(0);//找出0所在的根节点!由根节点就很容易得出它下面的叶子树!
cout << num[ans] << endl;
}
}
/*
100 4
2 1 2
5 10 13 11 12 14
2 0 1
2 99 2
200 2
1 5
5 1 2 3 4 5
1 0
100 4
2 1 2
5 1 1 11 15 2
2 0 1
3 2 9 1
0 0
*/