#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int uf_node[N];
int uf_rank[N];
int ans;
void uf_init(int n) {
  for (int i = 0; i <= n; i++) {
    uf_node[i] = i;
    uf_rank[i] = 0;
  }
}
int uf_find(int x) {
  if (x == uf_node[x]) return x;
  return uf_node[x] = uf_find(uf_node[x]);
}
void uf_unite(int x, int y) {
  x = uf_find(x);
  y = uf_find(y);
  if (x == y) return;
  ans--;
  if (uf_rank[x] < uf_rank[y]) {
    uf_node[x] = y;
  } else {
    uf_node[y] = x;
    if (uf_rank[x] == uf_rank[y]) uf_rank[x]++;
  }
}
bool uf_same(int x, int y) { return uf_find(x) == uf_find(y); }
vector<int> edge[N];
int main() {
  int n, m;
  scanf("%d%d", &n, &m);
  for (int i = 0; i <= m; i++) edge[i].clear();
  bool f = false;
  for (int i = 1; i <= n; i++) {
    int k;
    scanf("%d", &k);
    if (k) f = true;
    while (k--) {
      int u;
      scanf("%d", &u);
      edge[u].push_back(i);
    }
  }
  if (f == false)
    printf("%d\n", n);
  else {
    uf_init(100);
    ans = n;
    for (int i = 1; i <= m; i++) {
      for (int j = 1; j < edge[i].size(); j++)
        uf_unite(edge[i][j - 1], edge[i][j]);
    }
    printf("%d\n", ans - 1);
  }
}
