#include <bits/stdc++.h>
using namespace std;
vector<int> pset, set_size;
int disjointSetSize;
void initSet(int N) {
  disjointSetSize = N;
  set_size.assign(N, 1);
  pset.assign(N, 0);
  for (int i = 0; i < N; i++) pset[i] = i;
}
int findSet(int i) { return (pset[i] == i) ? i : (pset[i] = findSet(pset[i])); }
bool isSameSet(int i, int j) { return findSet(i) == findSet(j); }
void unionSet(int i, int j) {
  if (!isSameSet(i, j)) {
    disjointSetSize--;
    set_size[findSet(j)] += set_size[findSet(i)];
    pset[findSet(i)] = findSet(j);
  }
}
int sizeOfSet(int i) { return set_size[findSet(i)]; }
int main() {
  int N, M, K, x;
  vector<vector<int> > P;
  map<int, int> mapa;
  while (scanf("%d %d\n", &N, &M) != EOF) {
    P.clear();
    P.resize(N);
    mapa.clear();
    for (int i = 0; i < N; i++) P[i].clear();
    M = N;
    for (int i = 0; i < N; i++) {
      scanf("%d", &K);
      for (int j = 0; j < K; j++) {
        scanf("%d", &x);
        if (mapa.find(x) == mapa.end()) mapa[x] = M++;
        P[i].push_back(mapa[x]);
      }
    }
    if (M == N) M++;
    initSet(M);
    for (int i = 0; i < N; i++)
      for (int j = 0; j < (int)P[i].size(); j++) unionSet(i, P[i][j]);
    printf("%d\n", disjointSetSize - 1);
  }
  return 0;
}
