The "BerCorp" company has got n employees. These employees can use m approved official languages for the formal correspondence. The languages are numbered with integers from 1 to m. For each employee we have the list of languages, which he knows. This list could be empty, i. e. an employee may know no official languages. But the employees are willing to learn any number of official languages, as long as the company pays their lessons. A study course in one language for one employee costs 1 berdollar.

Find the minimum sum of money the company needs to spend so as any employee could correspond to any other one (their correspondence can be indirect, i. e. other employees can help out translating).

Input

The first line contains two integers n and m (2 ≤ n, m ≤ 100) — the number of employees and the number of languages.

Then n lines follow — each employee's language list. At the beginning of the i-th line is integer ki (0 ≤ ki ≤ m) — the number of languages the i-th employee knows. Next, the i-th line contains ki integers — aij (1 ≤ aij ≤ m) — the identifiers of languages the i-th employee knows. It is guaranteed that all the identifiers in one list are distinct. Note that an employee may know zero languages.

The numbers in the lines are separated by single spaces.

Output

Print a single integer — the minimum amount of money to pay so that in the end every employee could write a letter to every other one (other employees can help out translating).

Examples

Input

5 5
1 2
2 2 3
2 3 4
2 4 5
1 5


Output

0


Input

8 7
0
3 1 2 3
1 1
2 5 4
2 6 7
1 3
2 7 4
1 1


Output

2


Input

2 2
1 2
0


Output

1

Note

In the second sample the employee 1 can learn language 2, and employee 8 can learn language 4.

In the third sample employee 2 must learn language 2.
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

import java.io.*;
import java.math.BigInteger;
import java.util.*;
import java.text.*;

public class cf278c {

    static BufferedReader br;
    static Scanner sc;
    static PrintWriter out;

    public static void initA() {
        try {
            br = new BufferedReader(new InputStreamReader(System.in));
            //br = new BufferedReader(new FileReader("input.txt"));
            sc = new Scanner(System.in);
            //out = new PrintWriter("output.txt");
            out = new PrintWriter(System.out);
        } catch (Exception e) {
        }
    }

    public static void initB() {
        try {

            br = new BufferedReader(new FileReader("input.txt"));
            sc = new Scanner(new FileReader("input.txt"));
            out = new PrintWriter("output.txt");

        } catch (Exception e) {
        }
    }

    public static String getString() {
        try {
            return br.readLine();
        } catch (Exception e) {
        }
        return "";
    }

    public static Integer getInt() {
        try {
            return Integer.parseInt(br.readLine());
        } catch (Exception e) {
        }
        return 0;
    }

    public static Integer[] getIntArr() {
        try {
            StringTokenizer temp = new StringTokenizer(br.readLine());
            int n = temp.countTokens();
            Integer temp2[] = new Integer[n];
            for (int i = 0; i < n; i++) {
                temp2[i] = Integer.parseInt(temp.nextToken());
            }
            return temp2;
        } catch (Exception e) {
        }
        return null;
    }

    public static Long[] getLongArr() {
        try {
            StringTokenizer temp = new StringTokenizer(br.readLine());
            int n = temp.countTokens();
            Long temp2[] = new Long[n];
            for (int i = 0; i < n; i++) {
                temp2[i] = Long.parseLong(temp.nextToken());
            }
            return temp2;
        } catch (Exception e) {
        }
        return null;
    }

    public static String[] getStringArr() {
        try {
            StringTokenizer temp = new StringTokenizer(br.readLine());
            int n = temp.countTokens();
            String temp2[] = new String[n];
            for (int i = 0; i < n; i++) {
                temp2[i] = (temp.nextToken());
            }
            return temp2;
        } catch (Exception e) {
        }
        return null;
    }

    public static int getMax(Integer[] ar) {
        int t = ar[0];
        for (int i = 0; i < ar.length; i++) {
            if (ar[i] > t) {
                t = ar[i];
            }
        }
        return t;
    }

    public static void print(Object a) {
        out.println(a);
    }

    public static int nextInt() {
        return sc.nextInt();
    }

    public static double nextDouble() {
        return sc.nextDouble();
    }

    public static void main(String[] ar) {
        initA();
        solve();
        out.flush();
    }

    public static void solve() {
        Integer xx[] = getIntArr();
        int n = xx[0];
        HashSet<Integer>[] dataBahasa = new HashSet[n + 1];

        for (int i = 0; i <= n; i++) {
            dataBahasa[i] = new HashSet<Integer>();
        }

        for (int i = 1; i <= n; i++) {
            Integer te[] = getIntArr();

            for (int ii = 1; ii < te.length; ii++) {
                dataBahasa[i].add(te[ii]);
            }
       

        }
     

        ArrayList<HashSet<Integer>> arl_bhs = new ArrayList<HashSet<Integer>>();

       
        int noSkill = 0;
        for (int i = 1; i <= n; i++) {
            HashSet<Integer> temp = dataBahasa[i];
            if (temp.isEmpty()) {
                noSkill++;
                continue;
            } 
            
            boolean found = false;
            for (int k = 0; k < arl_bhs.size(); k++) {
                HashSet<Integer> temp2 = arl_bhs.get(k);
                //print(i + " " + temp2);

                for (int hihi : temp) {
                    if (temp2.contains(hihi)) {
                        found = true;
                        temp2.addAll(temp);
                        break;
                        /*
                        for (int hihi2 : temp) {
                            if (!temp2.contains(hihi2)) {
                                //print("MASUKKAN " + hihi + "ke " + k + " dari " + i);
                                temp2.add(hihi2);
                            }
                        }
                         * 
                         */
                    }
                }
            }
            if (!found && temp.size() > 0) {
                arl_bhs.add(temp);
            }



        }
        int pengurang = 0;
        HashSet<Integer> joined = new HashSet<Integer>();
        for (int k = 0; k < arl_bhs.size(); k++) {
            HashSet<Integer> temp = arl_bhs.get(k);
            //print(k + " = " + temp);
            int cur = joined.size();
            int pe = temp.size();
            joined.addAll(temp);
            if (joined.size() < cur + pe) {
                pengurang++;
            }
        }
        if (arl_bhs.size() == 1 || arl_bhs.isEmpty()) {
            print(noSkill);
            return;
        }
        int we = arl_bhs.size() - 1;
        //print(we + " " + pengurang);
        print(we - pengurang + noSkill);



    }
}
