#include <bits/stdc++.h>
using namespace std;
const long long MOD = 1e9 + 7;
const long long n_ = 1e5 + 1000;
const long double PI = acos(-1.0);
long long gcd(long long a, long long b) { return (a ? gcd(b % a, a) : b); }
long long power(long long a, long long n) {
  long long p = 1;
  while (n > 0) {
    if (n % 2) {
      p = p * a;
    }
    n >>= 1;
    a *= a;
  }
  return p;
}
long long power(long long a, long long n, long long mod) {
  long long p = 1;
  while (n > 0) {
    if (n % 2) {
      p = p * a;
      p %= mod;
    }
    n >>= 1;
    a *= a;
    a %= mod;
  }
  return p % mod;
}
bool vowel(char ch) {
  if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u')
    return true;
  else
    return false;
}
class UnionFind {
 private:
  vector<long long> p, rank, setSize;
  long long numSets;

 public:
  UnionFind(long long N) {
    setSize.assign(N, 1);
    numSets = N;
    rank.assign(N, 0);
    p.assign(N, 0);
    for (long long i = 0; i < N; i++) p[i] = i;
  }
  long long findSet(long long i) {
    return (p[i] == i) ? i : (p[i] = findSet(p[i]));
  }
  bool isSameSet(long long i, long long j) { return findSet(i) == findSet(j); }
  void unionSet(long long i, long long j) {
    if (!isSameSet(i, j)) {
      numSets--;
      long long x = findSet(i), y = findSet(j);
      if (rank[x] > rank[y]) {
        p[y] = x;
        setSize[x] += setSize[y];
      } else {
        p[x] = y;
        setSize[y] += setSize[x];
        if (rank[x] == rank[y]) rank[y]++;
      }
    }
  }
  long long numDisjointSets() { return numSets; }
  long long sizeOfSet(long long i) { return setSize[findSet(i)]; }
};
signed main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  long long n, m, s, x;
  cin >> n >> m;
  vector<long long> vec[n];
  long long cnt = 0;
  for (long long i = 0; i < n; i++) {
    cin >> s;
    for (long long j = 0; j < s; j++) {
      cin >> x;
      vec[i].push_back(x);
    }
  }
  for (long long i = 0; i < n; i++) cnt += vec[i].size();
  if (cnt == 0) {
    cout << n;
    return 0;
  }
  UnionFind UF(n);
  for (long long i = 0; i < n; i++) {
    for (long long j = i + 1; j < n; j++) {
      if (vec[i].size() == 0 || vec[j].size() == 0) continue;
      for (long long a = 0; a < vec[i].size(); a++) {
        for (long long b = 0; b < vec[j].size(); b++) {
          if (vec[i][a] == vec[j][b]) UF.unionSet(i, j);
        }
      }
    }
  }
  cout << UF.numDisjointSets() - 1;
  return 0;
}
