#include <bits/stdc++.h>
using namespace std;
struct classcomp {
  bool operator()(const int& lhs, const int& rhs) const { return lhs < rhs; }
};
set<int> g[101];
int inwhichset[101];
bool da[101];
vector<int> lang[101];
bool graf[101][101];
int main() {
  int n, m;
  cin >> n >> m;
  for (int i = 1; i <= n; ++i) {
    g[i].insert(i);
    inwhichset[i] = i;
    da[i] = true;
  }
  bool allzero = true;
  for (int i = 1; i <= n; ++i) {
    int k;
    cin >> k;
    if (k > 0) allzero = false;
    for (int j = 0; j < k; j++) {
      int t;
      cin >> t;
      lang[t].push_back(i);
    }
  }
  if (allzero) {
    cout << n << endl;
    return 0;
  }
  for (int i = 1; i <= n; ++i)
    for (int j = 1; j <= n; ++j) graf[i][j] = false;
  for (int l = 1; l <= m; ++l) {
    for (int i = 0; i < lang[l].size(); ++i) {
      for (int j = i + 1; j < lang[l].size(); ++j) {
        if (lang[l][i] != lang[l][j]) {
          graf[lang[l][i]][lang[l][j]] = true;
          graf[lang[l][j]][lang[l][i]] = true;
        }
      }
    }
  }
  int rez = n;
  int cont = true;
  while (cont) {
    cont = false;
    for (int i = 1; i <= n; ++i)
      for (int t = 1; t <= n; ++t)
        if (graf[i][t]) {
          int from = inwhichset[t];
          int to = inwhichset[i];
          if (to != from) {
            for (set<int>::iterator it = g[from].begin(); it != g[from].end();
                 it++) {
              g[to].insert(*it);
              inwhichset[*it] = to;
            }
            da[from] = false;
            rez--;
            cont = true;
          }
        }
  }
  cout << (rez - 1) << endl;
  return 0;
}
