import java.util.ArrayList;
import java.util.HashSet;
import java.util.Scanner;
public class LearningLanguagesA
{
    public static void main(String args[])
    {
        int cnt=0;
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int m=sc.nextInt();
        ArrayList<ArrayList<Integer>> ar=new ArrayList<>();
        ArrayList<Integer> sol[]=new ArrayList[100+1];
        for(int i=0;i<=m;i++)
        {
            sol[i]=new ArrayList<>();
        }
        for(int i=0;i<n;i++)
        {
            int ct=sc.nextInt();
            ArrayList<Integer> p=new ArrayList<>();
            for(int k=0;k<ct;k++)
            {
                p.add(sc.nextInt());
            }
            if(p.isEmpty())
            {
                cnt++;
            }
            else
            {
                ar.add(p);
            }
        }
        int arr[]=new int[100+1];
        int mt=0;int val;
        for(ArrayList<Integer> k : ar)
        {
            mt++;
            for(Integer m1: k)
            {
                sol[m1].add(mt);
            }
        }
        mt=0;
        for(ArrayList<Integer> k :sol)
        {
            val=0;
            if(k.size()>=1) {
                mt++;
                for (Integer m1 : k
                ) {
                    if (arr[m1] != 0) {
                        val = arr[m1];
                    }
                }
                if (val != 0) {
                    for (Integer m1 : k
                    ) {
                        arr[m1] = val;
                    }
                } else {
                    for (Integer m1 : k
                    ) {
                        arr[m1] = mt;
                    }
                }
            }
        }
        HashSet<Integer> hs=new HashSet<>();
        for(int i=1;i<=m;i++)
        {
            if(arr[i]!=0)
            hs.add(arr[i]);
        }
	if(hs.size()!=0)
        System.out.println(hs.size()+cnt-1);
	else
        {
            System.out.println(cnt);
        }
    }
}


import java.util.ArrayList;
import java.util.HashSet;
import java.util.Scanner;
public class LearningLanguagesA
{
    public static void main(String args[])
    {
        int cnt=0;
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int m=sc.nextInt();
        ArrayList<ArrayList<Integer>> ar=new ArrayList<>();
        ArrayList<Integer> sol[]=new ArrayList[m+1];
        for(int i=0;i<=m;i++)
        {
            sol[i]=new ArrayList<>();
        }
        for(int i=0;i<n;i++)
        {
            int ct=sc.nextInt();
            ArrayList<Integer> p=new ArrayList<>();
            for(int k=0;k<ct;k++)
            {
                p.add(sc.nextInt());
            }
            if(p.isEmpty())
            {
                cnt++;
            }
            else
            {
                ar.add(p);
            }
        }
        int arr[]=new int[n+1];
        int mt=0;int val;
        for(ArrayList<Integer> k : ar)
        {
            mt++;
            for(Integer m1: k)
            {
                sol[m1].add(mt);
            }
        }
        mt=0;
        for(ArrayList<Integer> k :sol)
        {
            val=0;
            if(k.size()>=1) {
                mt++;
                for (Integer m1 : k
                ) {
                    if (arr[m1] != 0) {
                        val = arr[m1];
                    }
                }
                if (val != 0) {
                    for (Integer m1 : k
                    ) {
                        arr[m1] = val;
                    }
                } else {
                    for (Integer m1 : k
                    ) {
                        arr[m1] = mt;
                    }
                }
            }
        }
        HashSet<Integer> hs=new HashSet<>();
        for(int i=1;i<=m;i++)
        {
            if(arr[i]!=0)
            hs.add(arr[i]);
        }
	if(hs.size()!=0)
        System.out.println(hs.size()+cnt-1);
	else
        {
            System.out.println(cnt);
        }
    }
}


package com.company;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Scanner;

public class LearningLanguagesA
{
    public static void main(String args[])
    {
        int cnt=0;
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int m=sc.nextInt();
        ArrayList<ArrayList<Integer>> ar=new ArrayList<>();
        ArrayList<Integer> sol[]=new ArrayList[m+1];
        for(int i=0;i<=m;i++)
        {
            sol[i]=new ArrayList<>();
        }
        //ArrayList<ArrayList<Integer>> sol=new ArrayList<>();
        for(int i=0;i<n;i++)
        {
            int ct=sc.nextInt();
            ArrayList<Integer> p=new ArrayList<>();
            for(int k=0;k<ct;k++)
            {
                p.add(sc.nextInt());
            }
            if(p.isEmpty())
            {
                cnt++;
               // System.out.println(cnt);
            }
            else
            {
                ar.add(p);
            }
           // System.out.println(cnt);
        }
        int temp=(int)Math.max(m,n);
        int arr[]=new int[temp+1];
        int mt=0;int val;
        for(ArrayList<Integer> k : ar)
        {
            //System.out.println(k);
            mt++;
            for(Integer m1: k)
            {
               // System.out.println(m1);
                sol[m1].add(mt);
            }
        }
        mt=0;
        for(ArrayList<Integer> k :sol)
        {
            val=0;
            //System.out.println(k);
            if(k.size()>=1) {
                mt++;
                for (Integer m1 : k
                ) {
                    //System.out.println(m1);
                    if (arr[m1] != 0) {
                        //System.out.println("Parent of "+m1+"="+arr[m1]);
                        val = arr[m1];
                    }
                }
                if (val != 0) {
                    //System.out.print("Setting value for ");
                    for (Integer m1 : k
                    ) {
                        //System.out.print(m1+" ");
                        arr[m1] = val;
                    }
                    //System.out.print("with "+val);
                } else {
                    for (Integer m1 : k
                    ) {
                        arr[m1] = mt;
                        //System.out.println("    "+arr[m1]);
                    }
                }
            }
        }
       // System.out.println();
        HashSet<Integer> hs=new HashSet<>();
        for(int i=1;i<=m;i++)
        {
            if(arr[i]!=0)
            hs.add(arr[i]);
            //System.out.print(arr[i]+" ");
        }
       // System.out.println();
        //System.out.println(hs.size()+" "+cnt);
        if(hs.size()!=0)
        System.out.println(hs.size()+cnt-1);
        else
        {
            System.out.println(cnt);
        }

    }
}


import java.util.ArrayList;
import java.util.HashSet;
import java.util.Scanner;

public class LearningLanguagesA
{
    public static void main(String args[])
    {
        int cnt=0;
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int m=sc.nextInt();
        ArrayList<ArrayList<Integer>> ar=new ArrayList<>();
        ArrayList<Integer> sol[]=new ArrayList[m+1];
        for(int i=0;i<=m;i++)
        {
            sol[i]=new ArrayList<>();
        }
        //ArrayList<ArrayList<Integer>> sol=new ArrayList<>();
        for(int i=0;i<n;i++)
        {
            int ct=sc.nextInt();
            ArrayList<Integer> p=new ArrayList<>();
            for(int k=0;k<ct;k++)
            {
                p.add(sc.nextInt());
            }
            if(p.isEmpty())
            {
                cnt++;
               // System.out.println(cnt);
            }
            else
            {
                ar.add(p);
            }
           // System.out.println(cnt);
        }
        int temp=(int)Math.max(m,n);
        int arr[]=new int[temp+1];
        int mt=0;int val;
        for(ArrayList<Integer> k : ar)
        {
            //System.out.println(k);
            mt++;
            for(Integer m1: k)
            {
               // System.out.println(m1);
                sol[m1].add(mt);
            }
        }
        mt=0;
        for(ArrayList<Integer> k :sol)
        {
            val=0;
            //System.out.println(k);
            if(k.size()>=1) {
                mt++;
                for (Integer m1 : k
                ) {
                    //System.out.println(m1);
                    if (arr[m1] != 0) {
                        //System.out.println("Parent of "+m1+"="+arr[m1]);
                        val = arr[m1];
                    }
                }
                if (val != 0) {
                    //System.out.print("Setting value for ");
                    for (Integer m1 : k
                    ) {
                        //System.out.print(m1+" ");
                        arr[m1] = val;
                    }
                    //System.out.print("with "+val);
                } else {
                    for (Integer m1 : k
                    ) {
                        arr[m1] = mt;
                        //System.out.println("    "+arr[m1]);
                    }
                }
            }
        }
       // System.out.println();
        HashSet<Integer> hs=new HashSet<>();
        for(int i=1;i<=m;i++)
        {
            if(arr[i]!=0)
            hs.add(arr[i]);
            //System.out.print(arr[i]+" ");
        }
       // System.out.println();
        //System.out.println(hs.size()+" "+cnt);
        if(hs.size()!=0)
        System.out.println(hs.size()+cnt-1);
        else
        {
            System.out.println(cnt);
        }

    }
}


import java.util.ArrayList;
import java.util.HashSet;
import java.util.Scanner;
public class LearningLanguagesA
{
    public static void main(String args[])
    {
        int cnt=0;
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int m=sc.nextInt();
        ArrayList<ArrayList<Integer>> ar=new ArrayList<>();
        ArrayList<Integer> sol[]=new ArrayList[m+1];
        for(int i=0;i<=m;i++)
        {
            sol[i]=new ArrayList<>();
        }
        for(int i=0;i<n;i++)
        {
            int ct=sc.nextInt();
            ArrayList<Integer> p=new ArrayList<>();
            for(int k=0;k<ct;k++)
            {
                p.add(sc.nextInt());
            }
            if(p.isEmpty())
            {
                cnt++;
            }
            else
            {
                ar.add(p);
            }
        }
        int arr[]=new int[m+1];
        int mt=0;int val;
        for(ArrayList<Integer> k : ar)
        {
            mt++;
            for(Integer m1: k)
            {
                sol[m1].add(mt);
            }
        }
        mt=0;
        for(ArrayList<Integer> k :sol)
        {
            val=0;
            if(k.size()>=1) {
                mt++;
                for (Integer m1 : k
                ) {
                    if (arr[m1] != 0) {
                        val = arr[m1];
                    }
                }
                if (val != 0) {
                    for (Integer m1 : k
                    ) {
                        arr[m1] = val;
                    }
                } else {
                    for (Integer m1 : k
                    ) {
                        arr[m1] = mt;
                    }
                }
            }
        }
        HashSet<Integer> hs=new HashSet<>();
        for(int i=1;i<=m;i++)
        {
            if(arr[i]!=0)
            hs.add(arr[i]);
        }
        System.out.println(hs.size()+cnt-1);
    }
}


import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;

public class LearningLanguagesA
{
    static HashSet<Integer> p;
    static ArrayList<Integer> ap;
    static ArrayList<Integer> arr[]=new ArrayList[201];
    static boolean vis[]=new boolean[201];
    public static void AddEdge(int src,int dest)
    {
        arr[src].add(dest);
        arr[dest].add(src);
    }
    public static void main(String args[])
    {
        int cnt=0;
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int m=sc.nextInt();
        int src=0;
        ArrayList<ArrayList<Integer>> ar=new ArrayList<>();
        for(int i=0;i<=200;i++)
        {
            arr[i]=new ArrayList<>();
        }
        Arrays.fill(vis,false);
        //=new HashSet<>();
        for(int i=0;i<n;i++) {
            int ct = sc.nextInt();
            if (ct == 0) {
                cnt++;
                continue;
            }
            ArrayList<Integer> pr=new ArrayList<>();
            for (int k = 0; k < ct; k++) {
                int q = sc.nextInt();
                pr.add(q);
            }
            ar.add(pr);
            src++;
        }
        p=new HashSet<>();
        int temp=0;
        for(ArrayList<Integer> a:ar)
        {
            if(!a.isEmpty())
            for(Integer ap:a)
            {
               // System.out.println("Adding edge from "+temp+" to"+ap);
                p.add(ap+src);
                AddEdge(temp,ap+src);
            }
            p.add(temp);
            temp++;
        }
        ap=new ArrayList<>(p);
        int ans=-1;
        while(ap.size()>0)
        {
            //System.out.println("Elements remaining "+ap.size());
            ans++;
            if(ans==-1)
            {
                solve(0);
            }
            else
            {
                solve(ap.get(0));
            }
        }
        if(ans!=-1)
        System.out.println(ans+cnt);
        else
        System.out.println(cnt);
    }
    public static void solve(int src)
    {
        if(!arr[src].isEmpty())
        for(Integer a:arr[src])
        {
            if(!vis[a])
            {
                vis[a]=true;
                //int temp=a;
                ap.remove(a);
                solve(a);
            }
        }
    }
}


import java.util.*;
import java.util.concurrent.LinkedBlockingDeque;
import java.io.*;
import java.lang.*;

	public class graph1
	{
		public static int n;
		public static ArrayList<Integer> adj[];
		public static ArrayList<Integer> adj2[];

		public static ArrayList<Integer> child[];
		public static boolean[] vis;
		public static ArrayList<Integer> pair;
		public static int[] par;
		public static int[] level;
		public static int[] set;
		public static int[] a;
		public static int[] ans;
		public static int[] init;
		public static int[] goal;

		public static int count;

		public static long INF = Long.MAX_VALUE/100;

		public static void main(String[] args)
		{
			InputReader in = new InputReader(System.in);
			PrintWriter pw = new PrintWriter(System.out);

	//		n = in.nextInt();
			n = in.nextInt();
			int m = in.nextInt();
			//int m = in.nextInt();
			//int s = in.nextInt();

			//children = new ArrayList[n+1];
			vis = new boolean[n+10005];
		//	par = new int[n+1];
			//set = new int[n+1];
			//level = new int[n+1];
			for(int i=0; i<n+10000; i++)
			{
				vis [i] = false;
				//par[i] = -1;
			}

			adj = new ArrayList[n+10005];
			for(int i=0;i<=n+1000;i++)
			{
				adj[i] = new ArrayList<Integer>();

			}

			int c2 = 0;
			for(int i=1; i<=n; i++)
			{
				int u = in.nextInt();
				if(u==0)
					c2++;
				for(int j=0; j<u; j++)
				{
					int v = in.nextInt()+101;
					adj[i].add(v);
					adj[v].add(i);

				}

			}
			int count = 0;
			for(int i=1; i<=n; i++)
			{
				if(!vis[i] && adj[i].size()>0) {

					bfs(i);
					count++;
				}
			}
			//pw.println(c2);
			if(count==0)
				count++;
			pw.println(c2+count-1);

			//code ends....
			pw.flush();
			pw.close();
		}

		public static void bfs(int x)
		{
			Queue<Integer> queue = new LinkedList<>();
			queue.add(x);
			vis[x] = true;

			while(!queue.isEmpty())
			{
				int last = queue.poll();
				//System.out.println(last);
				for(int p : adj[last])
				{
					if(!vis[p])
					{
						queue.add(p);
						vis[p] = true;

					}
				}
			}
		}

		public static int fbfs(int x)
		{
			Queue<Integer> queue = new LinkedList<>();
			queue.add(x);
			//level[x] = 1;
			int c = 0;
			//parent[x] = 0;
			//boolean[] vis = new boolean[n+1];
			vis[x] = true;
			while(!queue.isEmpty())
			{
				int last = queue.poll();
				for(int p : adj[last])
				{
					if(!vis[p])
					{
							//	children[last].add(a);
						queue.add(p);
					//	System.out.println(p+" ");
						vis[p] = true;
						c++;
					//	parent[a] = last;
						//level[a] = level[last]+1;

					}
				}
			}
			return c;
		}

		/*

		public static void fun(int s)
		{

			if(vis[s])
				return;
			set[s] = count;
			vis[s] = true;
			fun(a[s]);

		}

		public static int dfs(int s)
		{
			for(int i=0; i<=n; i++)
			{
				vis [i] = false;
				par[i] = -1;
				level[i] = 0;

			}
			Stack<Integer> stk = new Stack<>();
	 		stk.add(s);
			par[s] = 0;
			vis[s] = true;

			while(!stk.isEmpty())
			{
				int last = stk.pop();
			///	System.out.println(last);
				boolean f = false;
				for(int a : adj[last])
				{
					if(!vis[a])
					{
						//child[last].add(a);
						stk.add(a);
						par[a] = last;
						level[a] = level[last] +1;
						vis[a] = true;
					}
				}

			}
			int max = 0;
			int maxi = 0;
			for(int i=1; i<=n; i++)
			{
				if(level[i]>max)
				{
					max = level[i];
					maxi = i;
				}

			}
			return maxi;
		}

		 */

/*		public static void dfsrec(int s)
		{
			if(vis[s])
				return;

			vis[s] = true;
			int k = 0;
			for(int p: adj[s])
			{
				boolean f2 = false;
				if(!vis[p])
				{
					k++;
					dfsrec(p);
				}

			}
			par[s] = k;

		}

		public static int find(int i) {

			if(par[i]==-1)
				return i;
			else
				return find(par[i]);

		}

		 public static void union( int x, int y)
		    {
		        int xset = find( x);
		        int yset = find(y);
		        par[xset] = yset;
		    }

	 */

	/*	 public static boolean cycle(HashSet<pair> set) {

			 for(pair p: set)
			 {
				 int x = find(p.x);
				 int y = find(p.y);
				 if(x==y)
					 return true;

				 union(x, y);

			 }

			 return false;
		 }
		 */

		static class pair implements Comparable<pair>

		{
			Long x;
			Integer y;
			pair(long adj,int y)
			{

				this.x=adj;
				this.y=y;
			}

			public int compareTo(pair o) {
				//int result = x.compareTo(o.x);
				//if(result==0)
					int result = -y.compareTo(o.y);

				return result;
			}

			public String toString()
			{
				return x+" "+y;
			}

			public boolean equals(Object o)
			{
				if (o instanceof pair)
			    {
					pair p = (pair)o;
					return p.x == x && p.y == y ;
				}
				return false;
			}

			public int hashCode()
			{
				return new Long(x).hashCode()*31 + new Long(y).hashCode();
			}
		}

		static class triplet implements Comparable<triplet>
		{
			Integer x,y,z;
			triplet(int x,int y,int z)
			{
				this.x = x;
				this.y = y;
				this.z = z;
			}

			public  int compareTo(triplet o)
			{
				int result = x.compareTo(o.x);
				if(result==0)
					result =  y.compareTo(o.y);
				if(result==0)
					result = z.compareTo(o.z);

				return result;
			}

			public boolean equlas(Object o)
			{
				if(o instanceof triplet)
				{
					triplet p = (triplet)o;
					return x==p.x && y==p.y && z==p.z;
				}
				return false;
			}

			public String toString()
			{
				return x+" "+y+" "+z;
			}
			public int hashCode()
			{
				return new Long(x).hashCode()*31 + new Long(y).hashCode() + new Long(z).hashCode();
			}
		}

		static class InputReader
		{

			private final InputStream stream;
			private final byte[] buf = new byte[8192];
			private int curChar, snumChars;
			private SpaceCharFilter filter;

			public InputReader(InputStream stream)
			{
				this.stream = stream;
			}

			public int snext()
			{
				if (snumChars == -1)
					throw new InputMismatchException();
				if (curChar >= snumChars)
				{
					curChar = 0;
					try
					{
						snumChars = stream.read(buf);
					}
					catch (IOException e)
					{
						throw new InputMismatchException();
					}
					if (snumChars <= 0)
						return -1;
				}
				return buf[curChar++];
			}

			public int nextInt()
		    {
				int c = snext();
				while (isSpaceChar(c))
				{
					c = snext();
				}
				int sgn = 1;
				if (c == '-')
			    {
					sgn = -1;
					c = snext();
				}
				int res = 0;
				do
				{
					if (c < '0' || c > '9')
						throw new InputMismatchException();
					res *= 10;
					res += c - '0';
					c = snext();
				} while (!isSpaceChar(c));
				return res * sgn;
			}

			public long nextLong()
		    {
				int c = snext();
				while (isSpaceChar(c))
				{
					c = snext();
				}
				int sgn = 1;
				if (c == '-')
				{
					sgn = -1;
					c = snext();
				}
				long res = 0;
				do
				{
					if (c < '0' || c > '9')
						throw new InputMismatchException();
					res *= 10;
					res += c - '0';
					c = snext();
				} while (!isSpaceChar(c));
				return res * sgn;
			}

			public int[] nextIntArray(int n)
			{
				int a[] = new int[n];
				for (int i = 0; i < n; i++)
				{
					a[i] = nextInt();
				}
				return a;
			}

			public String readString()
		    {
				int c = snext();
				while (isSpaceChar(c))
				{
					c = snext();
				}
				StringBuilder res = new StringBuilder();
				do
				{
					res.appendCodePoint(c);
					c = snext();
				} while (!isSpaceChar(c));
				return res.toString();
			}

			public String nextLine()
			{
				int c = snext();
				while (isSpaceChar(c))
					c = snext();
				StringBuilder res = new StringBuilder();
				do
				{
					res.appendCodePoint(c);
					c = snext();
				} while (!isEndOfLine(c));
				return res.toString();
			}

			public boolean isSpaceChar(int c)
			{
				if (filter != null)
					return filter.isSpaceChar(c);
				return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
			}

			private boolean isEndOfLine(int c)
			{
				return c == '\n' || c == '\r' || c == -1;
			}

			public interface SpaceCharFilter
		    {
				public boolean isSpaceChar(int ch);
			}
		}

		public static long mod = 1000000007;
		public static int d;
		public static int p;
		public static int q;

		public static int[] suffle(int[] a,Random gen)
		{
			int n = a.length;
			for(int i=0;i<n;i++)
			{
				int ind = gen.nextInt(n-i)+i;
				int temp = a[ind];
				a[ind] = a[i];
				a[i] = temp;
			}
			return a;
		}

		public static void swap(int a, int b){
			int temp = a;
			a = b;
			b = temp;
		}

		public static HashSet<Integer> primeFactorization(int n)
		{
			HashSet<Integer> a =new HashSet<Integer>();
			for(int i=2;i*i<=n;i++)
			{
				while(n%i==0)
				{
					a.add(i);
					n/=i;
				}
			}
			if(n!=1)
				a.add(n);
			return a;
		}

		public static void sieve(boolean[] isPrime,int n)
		{
			for(int i=1;i<n;i++)
				isPrime[i] = true;

			isPrime[0] = false;
			isPrime[1] = false;

			for(int i=2;i*i<n;i++)
			{
				if(isPrime[i] == true)
				{
					for(int j=(2*i);j<n;j+=i)
						isPrime[j] = false;
				}
			}
		}

		public static int GCD(int a,int b)
		{
			if(b==0)
				return a;
			else
				return GCD(b,a%b);
		}

		public static long GCD(long a,long b)
		{
			if(b==0)
				return a;
			else
				return GCD(b,a%b);
		}

		public static void extendedEuclid(int A,int B)
		{
			if(B==0)
			{
				d = A;
				p = 1 ;
				q = 0;
			}
			else
			{
				extendedEuclid(B, A%B);
				int temp = p;
				p = q;
				q = temp - (A/B)*q;
			}
		}

		public static long LCM(long a,long b)
		{
			return (a*b)/GCD(a,b);
		}

		public static int LCM(int a,int b)
		{
			return (a*b)/GCD(a,b);
		}

		public static int binaryExponentiation(int x,int n)
		{
		    int result=1;
		    while(n>0)
		    {
		        if(n % 2 ==1)
		            result=result * x;
		        x=x*x;
		        n=n/2;
		    }
		    return result;
		}

		public static long binaryExponentiation(long x,long n)
		{
		    long result=1;
		    while(n>0)
		    {
		        if(n % 2 ==1)
		            result=result * x;
		        x=x*x;
		        n=n/2;
		    }
		    return result;
		}

		public static int modularExponentiation(int x,int n,int M)
		{
		    int result=1;
		    while(n>0)
		    {
		        if(n % 2 ==1)
		            result=(result * x)%M;
		        x=(x*x)%M;
		        n=n/2;
		    }
		    return result;
		}

		public static long modularExponentiation(long x,long n,long M)
		{
		    long result=1;
		    while(n>0)
		    {
		        if(n % 2 ==1)
		            result=(result * x)%M;
		        x=(x*x)%M;
		        n=n/2;
		    }
		    return result;
		}

		public static int modInverse(int A,int M)
		{
		    return modularExponentiation(A,M-2,M);
		}

		public static long modInverse(long A,long M)
		{
		    return modularExponentiation(A,M-2,M);
		}

		public static boolean isPrime(int n)
		{

		    if (n <= 1)  return false;
		    if (n <= 3)  return true;

		    if (n%2 == 0 || n%3 == 0)
		    	return false;

		    for (int i=5; i*i<=n; i=i+6)
		    {
		        if (n%i == 0 || n%(i+2) == 0)
		           return false;
		    }

		    return true;
		}

	}


import java.util.*;
import java.util.concurrent.LinkedBlockingDeque;
import java.io.*;
import java.lang.*;

	public class graph1
	{
		public static int n;
		public static ArrayList<Integer> adj[];
		public static ArrayList<Integer> adj2[];

		public static ArrayList<Integer> child[];
		public static boolean[] vis;
		public static ArrayList<Integer> pair;
		public static int[] par;
		public static int[] level;
		public static int[] set;
		public static int[] a;
		public static int[] ans;
		public static int[] init;
		public static int[] goal;

		public static int count;

		public static long INF = Long.MAX_VALUE/100;

		public static void main(String[] args)
		{
			InputReader in = new InputReader(System.in);
			PrintWriter pw = new PrintWriter(System.out);

	//		n = in.nextInt();
			n = in.nextInt();
			int m = in.nextInt();
			//int m = in.nextInt();
			//int s = in.nextInt();

			//children = new ArrayList[n+1];
			vis = new boolean[n+1005];
		//	par = new int[n+1];
			//set = new int[n+1];
			//level = new int[n+1];
			for(int i=0; i<n+1000; i++)
			{
				vis [i] = false;
				//par[i] = -1;
			}

			adj = new ArrayList[n+1005];
			for(int i=0;i<=n+1000;i++)
			{
				adj[i] = new ArrayList<Integer>();

			}

			for(int i=1; i<=n; i++)
			{
				int u = in.nextInt();
				for(int j=0; j<u; j++)
				{
					int v = in.nextInt()+1000;
					adj[i].add(v);
					adj[v].add(i);

				}

			}
			int count = 0;
			for(int i=1; i<=n; i++)
			{
				if(!vis[i]) {

					bfs(i);
					count++;
				}
			}
			pw.println(count-1);

			//code ends....
			pw.flush();
			pw.close();
		}

		public static void bfs(int x)
		{
			Queue<Integer> queue = new LinkedList<>();
			queue.add(x);
			vis[x] = true;

			while(!queue.isEmpty())
			{
				int last = queue.poll();
				//System.out.println(last);
				for(int p : adj[last])
				{
					if(!vis[p])
					{
						queue.add(p);
						vis[p] = true;

					}
				}
			}
		}

		public static int fbfs(int x)
		{
			Queue<Integer> queue = new LinkedList<>();
			queue.add(x);
			//level[x] = 1;
			int c = 0;
			//parent[x] = 0;
			//boolean[] vis = new boolean[n+1];
			vis[x] = true;
			while(!queue.isEmpty())
			{
				int last = queue.poll();
				for(int p : adj[last])
				{
					if(!vis[p])
					{
							//	children[last].add(a);
						queue.add(p);
					//	System.out.println(p+" ");
						vis[p] = true;
						c++;
					//	parent[a] = last;
						//level[a] = level[last]+1;

					}
				}
			}
			return c;
		}

		/*

		public static void fun(int s)
		{

			if(vis[s])
				return;
			set[s] = count;
			vis[s] = true;
			fun(a[s]);

		}

		public static int dfs(int s)
		{
			for(int i=0; i<=n; i++)
			{
				vis [i] = false;
				par[i] = -1;
				level[i] = 0;

			}
			Stack<Integer> stk = new Stack<>();
	 		stk.add(s);
			par[s] = 0;
			vis[s] = true;

			while(!stk.isEmpty())
			{
				int last = stk.pop();
			///	System.out.println(last);
				boolean f = false;
				for(int a : adj[last])
				{
					if(!vis[a])
					{
						//child[last].add(a);
						stk.add(a);
						par[a] = last;
						level[a] = level[last] +1;
						vis[a] = true;
					}
				}

			}
			int max = 0;
			int maxi = 0;
			for(int i=1; i<=n; i++)
			{
				if(level[i]>max)
				{
					max = level[i];
					maxi = i;
				}

			}
			return maxi;
		}

		 */

/*		public static void dfsrec(int s)
		{
			if(vis[s])
				return;

			vis[s] = true;
			int k = 0;
			for(int p: adj[s])
			{
				boolean f2 = false;
				if(!vis[p])
				{
					k++;
					dfsrec(p);
				}

			}
			par[s] = k;

		}

		public static int find(int i) {

			if(par[i]==-1)
				return i;
			else
				return find(par[i]);

		}

		 public static void union( int x, int y)
		    {
		        int xset = find( x);
		        int yset = find(y);
		        par[xset] = yset;
		    }

	 */

	/*	 public static boolean cycle(HashSet<pair> set) {

			 for(pair p: set)
			 {
				 int x = find(p.x);
				 int y = find(p.y);
				 if(x==y)
					 return true;

				 union(x, y);

			 }

			 return false;
		 }
		 */

		static class pair implements Comparable<pair>

		{
			Long x;
			Integer y;
			pair(long adj,int y)
			{

				this.x=adj;
				this.y=y;
			}

			public int compareTo(pair o) {
				//int result = x.compareTo(o.x);
				//if(result==0)
					int result = -y.compareTo(o.y);

				return result;
			}

			public String toString()
			{
				return x+" "+y;
			}

			public boolean equals(Object o)
			{
				if (o instanceof pair)
			    {
					pair p = (pair)o;
					return p.x == x && p.y == y ;
				}
				return false;
			}

			public int hashCode()
			{
				return new Long(x).hashCode()*31 + new Long(y).hashCode();
			}
		}

		static class triplet implements Comparable<triplet>
		{
			Integer x,y,z;
			triplet(int x,int y,int z)
			{
				this.x = x;
				this.y = y;
				this.z = z;
			}

			public  int compareTo(triplet o)
			{
				int result = x.compareTo(o.x);
				if(result==0)
					result =  y.compareTo(o.y);
				if(result==0)
					result = z.compareTo(o.z);

				return result;
			}

			public boolean equlas(Object o)
			{
				if(o instanceof triplet)
				{
					triplet p = (triplet)o;
					return x==p.x && y==p.y && z==p.z;
				}
				return false;
			}

			public String toString()
			{
				return x+" "+y+" "+z;
			}
			public int hashCode()
			{
				return new Long(x).hashCode()*31 + new Long(y).hashCode() + new Long(z).hashCode();
			}
		}

		static class InputReader
		{

			private final InputStream stream;
			private final byte[] buf = new byte[8192];
			private int curChar, snumChars;
			private SpaceCharFilter filter;

			public InputReader(InputStream stream)
			{
				this.stream = stream;
			}

			public int snext()
			{
				if (snumChars == -1)
					throw new InputMismatchException();
				if (curChar >= snumChars)
				{
					curChar = 0;
					try
					{
						snumChars = stream.read(buf);
					}
					catch (IOException e)
					{
						throw new InputMismatchException();
					}
					if (snumChars <= 0)
						return -1;
				}
				return buf[curChar++];
			}

			public int nextInt()
		    {
				int c = snext();
				while (isSpaceChar(c))
				{
					c = snext();
				}
				int sgn = 1;
				if (c == '-')
			    {
					sgn = -1;
					c = snext();
				}
				int res = 0;
				do
				{
					if (c < '0' || c > '9')
						throw new InputMismatchException();
					res *= 10;
					res += c - '0';
					c = snext();
				} while (!isSpaceChar(c));
				return res * sgn;
			}

			public long nextLong()
		    {
				int c = snext();
				while (isSpaceChar(c))
				{
					c = snext();
				}
				int sgn = 1;
				if (c == '-')
				{
					sgn = -1;
					c = snext();
				}
				long res = 0;
				do
				{
					if (c < '0' || c > '9')
						throw new InputMismatchException();
					res *= 10;
					res += c - '0';
					c = snext();
				} while (!isSpaceChar(c));
				return res * sgn;
			}

			public int[] nextIntArray(int n)
			{
				int a[] = new int[n];
				for (int i = 0; i < n; i++)
				{
					a[i] = nextInt();
				}
				return a;
			}

			public String readString()
		    {
				int c = snext();
				while (isSpaceChar(c))
				{
					c = snext();
				}
				StringBuilder res = new StringBuilder();
				do
				{
					res.appendCodePoint(c);
					c = snext();
				} while (!isSpaceChar(c));
				return res.toString();
			}

			public String nextLine()
			{
				int c = snext();
				while (isSpaceChar(c))
					c = snext();
				StringBuilder res = new StringBuilder();
				do
				{
					res.appendCodePoint(c);
					c = snext();
				} while (!isEndOfLine(c));
				return res.toString();
			}

			public boolean isSpaceChar(int c)
			{
				if (filter != null)
					return filter.isSpaceChar(c);
				return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
			}

			private boolean isEndOfLine(int c)
			{
				return c == '\n' || c == '\r' || c == -1;
			}

			public interface SpaceCharFilter
		    {
				public boolean isSpaceChar(int ch);
			}
		}

		public static long mod = 1000000007;
		public static int d;
		public static int p;
		public static int q;

		public static int[] suffle(int[] a,Random gen)
		{
			int n = a.length;
			for(int i=0;i<n;i++)
			{
				int ind = gen.nextInt(n-i)+i;
				int temp = a[ind];
				a[ind] = a[i];
				a[i] = temp;
			}
			return a;
		}

		public static void swap(int a, int b){
			int temp = a;
			a = b;
			b = temp;
		}

		public static HashSet<Integer> primeFactorization(int n)
		{
			HashSet<Integer> a =new HashSet<Integer>();
			for(int i=2;i*i<=n;i++)
			{
				while(n%i==0)
				{
					a.add(i);
					n/=i;
				}
			}
			if(n!=1)
				a.add(n);
			return a;
		}

		public static void sieve(boolean[] isPrime,int n)
		{
			for(int i=1;i<n;i++)
				isPrime[i] = true;

			isPrime[0] = false;
			isPrime[1] = false;

			for(int i=2;i*i<n;i++)
			{
				if(isPrime[i] == true)
				{
					for(int j=(2*i);j<n;j+=i)
						isPrime[j] = false;
				}
			}
		}

		public static int GCD(int a,int b)
		{
			if(b==0)
				return a;
			else
				return GCD(b,a%b);
		}

		public static long GCD(long a,long b)
		{
			if(b==0)
				return a;
			else
				return GCD(b,a%b);
		}

		public static void extendedEuclid(int A,int B)
		{
			if(B==0)
			{
				d = A;
				p = 1 ;
				q = 0;
			}
			else
			{
				extendedEuclid(B, A%B);
				int temp = p;
				p = q;
				q = temp - (A/B)*q;
			}
		}

		public static long LCM(long a,long b)
		{
			return (a*b)/GCD(a,b);
		}

		public static int LCM(int a,int b)
		{
			return (a*b)/GCD(a,b);
		}

		public static int binaryExponentiation(int x,int n)
		{
		    int result=1;
		    while(n>0)
		    {
		        if(n % 2 ==1)
		            result=result * x;
		        x=x*x;
		        n=n/2;
		    }
		    return result;
		}

		public static long binaryExponentiation(long x,long n)
		{
		    long result=1;
		    while(n>0)
		    {
		        if(n % 2 ==1)
		            result=result * x;
		        x=x*x;
		        n=n/2;
		    }
		    return result;
		}

		public static int modularExponentiation(int x,int n,int M)
		{
		    int result=1;
		    while(n>0)
		    {
		        if(n % 2 ==1)
		            result=(result * x)%M;
		        x=(x*x)%M;
		        n=n/2;
		    }
		    return result;
		}

		public static long modularExponentiation(long x,long n,long M)
		{
		    long result=1;
		    while(n>0)
		    {
		        if(n % 2 ==1)
		            result=(result * x)%M;
		        x=(x*x)%M;
		        n=n/2;
		    }
		    return result;
		}

		public static int modInverse(int A,int M)
		{
		    return modularExponentiation(A,M-2,M);
		}

		public static long modInverse(long A,long M)
		{
		    return modularExponentiation(A,M-2,M);
		}

		public static boolean isPrime(int n)
		{

		    if (n <= 1)  return false;
		    if (n <= 3)  return true;

		    if (n%2 == 0 || n%3 == 0)
		    	return false;

		    for (int i=5; i*i<=n; i=i+6)
		    {
		        if (n%i == 0 || n%(i+2) == 0)
		           return false;
		    }

		    return true;
		}

	}


import java.util.*;
import java.util.concurrent.LinkedBlockingDeque;
import java.io.*;
import java.lang.*;

	public class graph1
	{
		public static int n;
		public static ArrayList<Integer> adj[];
		public static ArrayList<Integer> adj2[];

		public static ArrayList<Integer> child[];
		public static boolean[] vis;
		public static ArrayList<Integer> pair;
		public static int[] par;
		public static int[] level;
		public static int[] set;
		public static int[] a;
		public static int[] ans;
		public static int[] init;
		public static int[] goal;

		public static int count;

		public static long INF = Long.MAX_VALUE/100;

		public static void main(String[] args)
		{
			InputReader in = new InputReader(System.in);
			PrintWriter pw = new PrintWriter(System.out);

	//		n = in.nextInt();
			n = in.nextInt();
			int m = in.nextInt();
			//int m = in.nextInt();
			//int s = in.nextInt();

			//children = new ArrayList[n+1];
			vis = new boolean[n+1005];
		//	par = new int[n+1];
			//set = new int[n+1];
			//level = new int[n+1];
			for(int i=0; i<n+1000; i++)
			{
				vis [i] = false;
				//par[i] = -1;
			}

			adj = new ArrayList[n+1005];
			for(int i=0;i<=n+1000;i++)
			{
				adj[i] = new ArrayList<Integer>();

			}

			int c2 = 0;
			for(int i=1; i<=n; i++)
			{
				int u = in.nextInt();
				if(u==0)
					c2++;
				for(int j=0; j<u; j++)
				{
					int v = in.nextInt()+1000;
					adj[i].add(v);
					adj[v].add(i);

				}

			}
			int count = 0;
			for(int i=1; i<=n; i++)
			{
				if(!vis[i] && adj[i].size()>0) {

					bfs(i);
					count++;
				}
			}
			//pw.println(c2);
			if(count==0)
				count++;
			pw.println(c2+count-1);

			//code ends....
			pw.flush();
			pw.close();
		}

		public static void bfs(int x)
		{
			Queue<Integer> queue = new LinkedList<>();
			queue.add(x);
			vis[x] = true;

			while(!queue.isEmpty())
			{
				int last = queue.poll();
				//System.out.println(last);
				for(int p : adj[last])
				{
					if(!vis[p])
					{
						queue.add(p);
						vis[p] = true;

					}
				}
			}
		}

		public static int fbfs(int x)
		{
			Queue<Integer> queue = new LinkedList<>();
			queue.add(x);
			//level[x] = 1;
			int c = 0;
			//parent[x] = 0;
			//boolean[] vis = new boolean[n+1];
			vis[x] = true;
			while(!queue.isEmpty())
			{
				int last = queue.poll();
				for(int p : adj[last])
				{
					if(!vis[p])
					{
							//	children[last].add(a);
						queue.add(p);
					//	System.out.println(p+" ");
						vis[p] = true;
						c++;
					//	parent[a] = last;
						//level[a] = level[last]+1;

					}
				}
			}
			return c;
		}

		/*

		public static void fun(int s)
		{

			if(vis[s])
				return;
			set[s] = count;
			vis[s] = true;
			fun(a[s]);

		}

		public static int dfs(int s)
		{
			for(int i=0; i<=n; i++)
			{
				vis [i] = false;
				par[i] = -1;
				level[i] = 0;

			}
			Stack<Integer> stk = new Stack<>();
	 		stk.add(s);
			par[s] = 0;
			vis[s] = true;

			while(!stk.isEmpty())
			{
				int last = stk.pop();
			///	System.out.println(last);
				boolean f = false;
				for(int a : adj[last])
				{
					if(!vis[a])
					{
						//child[last].add(a);
						stk.add(a);
						par[a] = last;
						level[a] = level[last] +1;
						vis[a] = true;
					}
				}

			}
			int max = 0;
			int maxi = 0;
			for(int i=1; i<=n; i++)
			{
				if(level[i]>max)
				{
					max = level[i];
					maxi = i;
				}

			}
			return maxi;
		}

		 */

/*		public static void dfsrec(int s)
		{
			if(vis[s])
				return;

			vis[s] = true;
			int k = 0;
			for(int p: adj[s])
			{
				boolean f2 = false;
				if(!vis[p])
				{
					k++;
					dfsrec(p);
				}

			}
			par[s] = k;

		}

		public static int find(int i) {

			if(par[i]==-1)
				return i;
			else
				return find(par[i]);

		}

		 public static void union( int x, int y)
		    {
		        int xset = find( x);
		        int yset = find(y);
		        par[xset] = yset;
		    }

	 */

	/*	 public static boolean cycle(HashSet<pair> set) {

			 for(pair p: set)
			 {
				 int x = find(p.x);
				 int y = find(p.y);
				 if(x==y)
					 return true;

				 union(x, y);

			 }

			 return false;
		 }
		 */

		static class pair implements Comparable<pair>

		{
			Long x;
			Integer y;
			pair(long adj,int y)
			{

				this.x=adj;
				this.y=y;
			}

			public int compareTo(pair o) {
				//int result = x.compareTo(o.x);
				//if(result==0)
					int result = -y.compareTo(o.y);

				return result;
			}

			public String toString()
			{
				return x+" "+y;
			}

			public boolean equals(Object o)
			{
				if (o instanceof pair)
			    {
					pair p = (pair)o;
					return p.x == x && p.y == y ;
				}
				return false;
			}

			public int hashCode()
			{
				return new Long(x).hashCode()*31 + new Long(y).hashCode();
			}
		}

		static class triplet implements Comparable<triplet>
		{
			Integer x,y,z;
			triplet(int x,int y,int z)
			{
				this.x = x;
				this.y = y;
				this.z = z;
			}

			public  int compareTo(triplet o)
			{
				int result = x.compareTo(o.x);
				if(result==0)
					result =  y.compareTo(o.y);
				if(result==0)
					result = z.compareTo(o.z);

				return result;
			}

			public boolean equlas(Object o)
			{
				if(o instanceof triplet)
				{
					triplet p = (triplet)o;
					return x==p.x && y==p.y && z==p.z;
				}
				return false;
			}

			public String toString()
			{
				return x+" "+y+" "+z;
			}
			public int hashCode()
			{
				return new Long(x).hashCode()*31 + new Long(y).hashCode() + new Long(z).hashCode();
			}
		}

		static class InputReader
		{

			private final InputStream stream;
			private final byte[] buf = new byte[8192];
			private int curChar, snumChars;
			private SpaceCharFilter filter;

			public InputReader(InputStream stream)
			{
				this.stream = stream;
			}

			public int snext()
			{
				if (snumChars == -1)
					throw new InputMismatchException();
				if (curChar >= snumChars)
				{
					curChar = 0;
					try
					{
						snumChars = stream.read(buf);
					}
					catch (IOException e)
					{
						throw new InputMismatchException();
					}
					if (snumChars <= 0)
						return -1;
				}
				return buf[curChar++];
			}

			public int nextInt()
		    {
				int c = snext();
				while (isSpaceChar(c))
				{
					c = snext();
				}
				int sgn = 1;
				if (c == '-')
			    {
					sgn = -1;
					c = snext();
				}
				int res = 0;
				do
				{
					if (c < '0' || c > '9')
						throw new InputMismatchException();
					res *= 10;
					res += c - '0';
					c = snext();
				} while (!isSpaceChar(c));
				return res * sgn;
			}

			public long nextLong()
		    {
				int c = snext();
				while (isSpaceChar(c))
				{
					c = snext();
				}
				int sgn = 1;
				if (c == '-')
				{
					sgn = -1;
					c = snext();
				}
				long res = 0;
				do
				{
					if (c < '0' || c > '9')
						throw new InputMismatchException();
					res *= 10;
					res += c - '0';
					c = snext();
				} while (!isSpaceChar(c));
				return res * sgn;
			}

			public int[] nextIntArray(int n)
			{
				int a[] = new int[n];
				for (int i = 0; i < n; i++)
				{
					a[i] = nextInt();
				}
				return a;
			}

			public String readString()
		    {
				int c = snext();
				while (isSpaceChar(c))
				{
					c = snext();
				}
				StringBuilder res = new StringBuilder();
				do
				{
					res.appendCodePoint(c);
					c = snext();
				} while (!isSpaceChar(c));
				return res.toString();
			}

			public String nextLine()
			{
				int c = snext();
				while (isSpaceChar(c))
					c = snext();
				StringBuilder res = new StringBuilder();
				do
				{
					res.appendCodePoint(c);
					c = snext();
				} while (!isEndOfLine(c));
				return res.toString();
			}

			public boolean isSpaceChar(int c)
			{
				if (filter != null)
					return filter.isSpaceChar(c);
				return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
			}

			private boolean isEndOfLine(int c)
			{
				return c == '\n' || c == '\r' || c == -1;
			}

			public interface SpaceCharFilter
		    {
				public boolean isSpaceChar(int ch);
			}
		}

		public static long mod = 1000000007;
		public static int d;
		public static int p;
		public static int q;

		public static int[] suffle(int[] a,Random gen)
		{
			int n = a.length;
			for(int i=0;i<n;i++)
			{
				int ind = gen.nextInt(n-i)+i;
				int temp = a[ind];
				a[ind] = a[i];
				a[i] = temp;
			}
			return a;
		}

		public static void swap(int a, int b){
			int temp = a;
			a = b;
			b = temp;
		}

		public static HashSet<Integer> primeFactorization(int n)
		{
			HashSet<Integer> a =new HashSet<Integer>();
			for(int i=2;i*i<=n;i++)
			{
				while(n%i==0)
				{
					a.add(i);
					n/=i;
				}
			}
			if(n!=1)
				a.add(n);
			return a;
		}

		public static void sieve(boolean[] isPrime,int n)
		{
			for(int i=1;i<n;i++)
				isPrime[i] = true;

			isPrime[0] = false;
			isPrime[1] = false;

			for(int i=2;i*i<n;i++)
			{
				if(isPrime[i] == true)
				{
					for(int j=(2*i);j<n;j+=i)
						isPrime[j] = false;
				}
			}
		}

		public static int GCD(int a,int b)
		{
			if(b==0)
				return a;
			else
				return GCD(b,a%b);
		}

		public static long GCD(long a,long b)
		{
			if(b==0)
				return a;
			else
				return GCD(b,a%b);
		}

		public static void extendedEuclid(int A,int B)
		{
			if(B==0)
			{
				d = A;
				p = 1 ;
				q = 0;
			}
			else
			{
				extendedEuclid(B, A%B);
				int temp = p;
				p = q;
				q = temp - (A/B)*q;
			}
		}

		public static long LCM(long a,long b)
		{
			return (a*b)/GCD(a,b);
		}

		public static int LCM(int a,int b)
		{
			return (a*b)/GCD(a,b);
		}

		public static int binaryExponentiation(int x,int n)
		{
		    int result=1;
		    while(n>0)
		    {
		        if(n % 2 ==1)
		            result=result * x;
		        x=x*x;
		        n=n/2;
		    }
		    return result;
		}

		public static long binaryExponentiation(long x,long n)
		{
		    long result=1;
		    while(n>0)
		    {
		        if(n % 2 ==1)
		            result=result * x;
		        x=x*x;
		        n=n/2;
		    }
		    return result;
		}

		public static int modularExponentiation(int x,int n,int M)
		{
		    int result=1;
		    while(n>0)
		    {
		        if(n % 2 ==1)
		            result=(result * x)%M;
		        x=(x*x)%M;
		        n=n/2;
		    }
		    return result;
		}

		public static long modularExponentiation(long x,long n,long M)
		{
		    long result=1;
		    while(n>0)
		    {
		        if(n % 2 ==1)
		            result=(result * x)%M;
		        x=(x*x)%M;
		        n=n/2;
		    }
		    return result;
		}

		public static int modInverse(int A,int M)
		{
		    return modularExponentiation(A,M-2,M);
		}

		public static long modInverse(long A,long M)
		{
		    return modularExponentiation(A,M-2,M);
		}

		public static boolean isPrime(int n)
		{

		    if (n <= 1)  return false;
		    if (n <= 3)  return true;

		    if (n%2 == 0 || n%3 == 0)
		    	return false;

		    for (int i=5; i*i<=n; i=i+6)
		    {
		        if (n%i == 0 || n%(i+2) == 0)
		           return false;
		    }

		    return true;
		}

	}


import java.util.*;
import java.io.*;

public class Solution {
	public static void main (String[] args) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String[] temp=br.readLine().trim().split(" ");
		int V=Integer.parseInt(temp[0]);
		int totalLanguages=Integer.parseInt(temp[1]);

		ArrayList<ArrayList<Integer>> languagesKnown=new ArrayList<>();
		for(int i=0;i<=V;i++)
		{
		    languagesKnown.add(new ArrayList<>());
		}
		for(int i=1;i<=V;i++)
		{
		    temp=br.readLine().trim().split(" ");

		    int numLanguagesKnown=Integer.parseInt(temp[0]);
		    for(int j=1;j<=numLanguagesKnown;j++)
		    {
		        int languageID=Integer.parseInt(temp[j]);
		        languagesKnown.get(i).add(languageID);
		    }
		}
		System.out.println(minCost(languagesKnown,totalLanguages));
	}
	public static int minCost(ArrayList<ArrayList<Integer>> languagesKnown,int totalLanguages)
	{
	    int count=0;
	    int V=languagesKnown.size()-1;
	    for(int i=1;i<=V;i++)
	    {
	        if(languagesKnown.get(i).size()==0)
	        {
	            count++;
	        }
	    }
	    if(count==V)
	    {
	        return V;
	    }
	    DSU graph=new DSU(V);
	    int[] personKnowingLanguage=new int[totalLanguages+1];
	    for(int i=1;i<=V;i++)
	    {
	        for(int j=0;j<languagesKnown.get(i).size();j++)
	        {
	            int languageID=languagesKnown.get(i).get(j);
	            if(personKnowingLanguage[languageID]!=0)
	            {
	                graph.makeUnion(personKnowingLanguage[languageID],i);
	            }
	            else{
	                personKnowingLanguage[languageID]=i;
	            }
	        }
	    }
	    return graph.numComponents()-1;
	}
}

class DSU{
    private int[] parent;
    private int[]size;
    public DSU(int V)
    {
        parent=new int[V+1];
        size=new int[V+1];

        for(int i=1;i<=V;i++)
        {
            parent[i]=i;
            size[i]=1;
        }
    }
    public int getParent(int vertex)
    {
        int temp=vertex;
        while(parent[vertex]!=vertex)
        {
            vertex=parent[vertex];
        }
        parent[temp]=vertex;
        return vertex;
    }
    public void makeUnion(int u,int v)
    {
        int parent1=getParent(u);
        int parent2=getParent(v);

        if(parent1==parent2)
        {
            return;
        }
        int size1=size[parent1];
        int size2=size[parent2];

        if(size2<size1)
        {
            parent[parent2]=parent1;
            size[parent1]+=size[parent2];
        }
        else{
            parent[parent1]=parent2;
            size[parent2]+=size[parent1];
        }
    }
    public int numComponents()
    {
        int count=0;
        int V=this.parent.length-1;
        for(int i=1;i<=V;i++)
        {
            if(parent[i]==i)
            {
                count++;
            }
        }
        return count;
    }
}


import java.util.*;
import java.io.*;

public class Solution {
	public static void main (String[] args) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String[] temp=br.readLine().trim().split(" ");
		int V=Integer.parseInt(temp[0]);
		int E=Integer.parseInt(temp[1]);

		ArrayList<ArrayList<Integer>> languagesKnown=new ArrayList<>();
		for(int i=0;i<=V;i++)
		{
		    languagesKnown.add(new ArrayList<>());
		}
		for(int i=1;i<=V;i++)
		{
		    temp=br.readLine().trim().split(" ");

		    int numLanguagesKnown=Integer.parseInt(temp[0]);
		    for(int j=1;j<=numLanguagesKnown;j++)
		    {
		        int languageID=Integer.parseInt(temp[j]);
		        languagesKnown.get(i).add(languageID);
		    }
		}
		System.out.println(minCost(languagesKnown));
	}
	public static int minCost(ArrayList<ArrayList<Integer>> languagesKnown)
	{
	    int V=languagesKnown.size()-1;
	    DSU graph=new DSU(V);
	    for(int i=1;i<=V;i++)
	    {
	        for(int j=0;j<languagesKnown.get(i).size();j++)
	        {
	            int languageID=languagesKnown.get(i).get(j);
	            for(int k=1;k<i;k++)
	            {
	                for(int l=0;l<languagesKnown.get(k).size();l++)
	                {
	                    if(languagesKnown.get(k).get(l)==languageID)
	                    {
	                        graph.makeUnion(k,i);
	                    }
	                }
	            }
	        }
	    }
	    return graph.numComponents()-1;
	}
}

class DSU{
    private int[] parent;
    private int[]size;
    public DSU(int V)
    {
        parent=new int[V+1];
        size=new int[V+1];

        for(int i=1;i<=V;i++)
        {
            parent[i]=i;
            size[i]=1;
        }
    }
    public int getParent(int vertex)
    {
        int temp=vertex;
        while(parent[vertex]!=vertex)
        {
            vertex=parent[vertex];
        }
        parent[temp]=vertex;
        return vertex;
    }
    public void makeUnion(int u,int v)
    {
        int parent1=getParent(u);
        int parent2=getParent(v);

        if(parent1==parent2)
        {
            return;
        }
        int size1=size[parent1];
        int size2=size[parent2];

        if(size2<size1)
        {
            parent[parent2]=parent1;
            size[parent1]+=size[parent2];
        }
        else{
            parent[parent1]=parent2;
            size[parent2]+=size[parent1];
        }
    }
    public int numComponents()
    {
        int count=0;
        int V=this.parent.length-1;
        for(int i=1;i<=V;i++)
        {
            if(parent[i]==i)
            {
                count++;
            }
        }
        return count;
    }
}


import java.util.*;
import java.io.*;

public class Solution {
	public static void main (String[] args) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String[] temp=br.readLine().trim().split(" ");
		int V=Integer.parseInt(temp[0]);
		int E=Integer.parseInt(temp[1]);

		ArrayList<ArrayList<Integer>> languagesKnown=new ArrayList<>();
		for(int i=0;i<=V;i++)
		{
		    languagesKnown.add(new ArrayList<>());
		}
		for(int i=1;i<=V;i++)
		{
		    temp=br.readLine().trim().split(" ");

		    int numLanguagesKnown=Integer.parseInt(temp[0]);
		    for(int j=1;j<=numLanguagesKnown;j++)
		    {
		        int languageID=Integer.parseInt(temp[j]);
		        languagesKnown.get(i).add(languageID);
		    }
		}
		System.out.println(minCost(languagesKnown));
	}
	public static int minCost(ArrayList<ArrayList<Integer>> languagesKnown)
	{
	    int count=0;
	    int V=languagesKnown.size()-1;
	    for(int i=1;i<=V;i++)
	    {
	        if(languagesKnown.get(i).size()==0)
	        {
	            count++;
	        }
	    }
	    if(count==V)
	    {
	        return V;
	    }
	    DSU graph=new DSU(V);
	    for(int i=1;i<=V;i++)
	    {
	        for(int j=0;j<languagesKnown.get(i).size();j++)
	        {
	            int languageID=languagesKnown.get(i).get(j);
	            for(int k=1;k<i;k++)
	            {
	                for(int l=0;l<languagesKnown.get(k).size();l++)
	                {
	                    if(languagesKnown.get(k).get(l)==languageID)
	                    {
	                        graph.makeUnion(k,i);
	                    }
	                }
	            }
	        }
	    }
	    return graph.numComponents()-1;
	}
}

class DSU{
    private int[] parent;
    private int[]size;
    public DSU(int V)
    {
        parent=new int[V+1];
        size=new int[V+1];

        for(int i=1;i<=V;i++)
        {
            parent[i]=i;
            size[i]=1;
        }
    }
    public int getParent(int vertex)
    {
        int temp=vertex;
        while(parent[vertex]!=vertex)
        {
            vertex=parent[vertex];
        }
        parent[temp]=vertex;
        return vertex;
    }
    public void makeUnion(int u,int v)
    {
        int parent1=getParent(u);
        int parent2=getParent(v);

        if(parent1==parent2)
        {
            return;
        }
        int size1=size[parent1];
        int size2=size[parent2];

        if(size2<size1)
        {
            parent[parent2]=parent1;
            size[parent1]+=size[parent2];
        }
        else{
            parent[parent1]=parent2;
            size[parent2]+=size[parent1];
        }
    }
    public int numComponents()
    {
        int count=0;
        int V=this.parent.length-1;
        for(int i=1;i<=V;i++)
        {
            if(parent[i]==i)
            {
                count++;
            }
        }
        return count;
    }
}


import java.io.*;
import java.util.*;
public class A277
{
    public static void main(String args[])throws IOException
    {
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        String s[]=br.readLine().trim().split(" ");
        int n=Integer.parseInt(s[0]);
        int m=Integer.parseInt(s[1]);
        HashMap<Integer,ArrayList<Integer>> emp=new HashMap<>();
        HashMap<Integer,ArrayList<Integer>> lang=new HashMap<>();
        HashMap<Integer,ArrayList<Integer>> map=new HashMap<>();
        int id[]=new int[n+1];

        for(int i=1;i<=m;i++)
        {
            lang.put(i,new ArrayList<Integer>());
            //map.put(i,new ArrayList<Integer>());
        }
        int c=0;
        for(int i=1;i<=n;i++)
        {
            emp.put(i,new ArrayList<Integer>());
            map.put(i,new ArrayList<Integer>());
            s=br.readLine().trim().split(" ");
            int k=Integer.parseInt(s[0]);
            if(k!=0)
            {
                for(int j=1;j<=k;j++)
                {
                    emp.get(i).add(Integer.parseInt(s[j]));
                    lang.get(Integer.parseInt(s[j])).add(i);
                }
            }
            else
                c++;
        }
        //System.out.println(emp+" "+lang);
        int arr[][]=new int[n+1][m+1];
        for(int i:emp.keySet())
        {
            //map.put(i,new ArrayList<Integer>());
            List<Integer> list=emp.get(i);
            for(int j:list)
            {

                for(int k:lang.get(j))
                {
                    if(arr[k][j]==0)
                    {
                        if(i!=k)
                        {
                            map.get(i).add(k);
                            map.get(k).add(i);
                        }
                        arr[k][j]=1;
                    }
                }
            }
            //System.out.println(map);
        }
        //System.out.println(map);
        boolean visit[]=new boolean[n+1];int conn=0;
        for(int i=1;i<=m;i++)
        {
            if(!visit[i])
            {
                conn++;
                visit[i]=true;
                Stack st=new Stack();
                st.push(i);
                while(st.size()!=0)
                {
                    int a=(Integer)st.pop();
                    for(int j:map.get(a))
                    {
                        if(!visit[j])
                        {
                            visit[j]=true;
                            st.push(j);

                        }
                    }
                }
            }
        }
        if(c==n)
            System.out.println(c);
        else
            System.out.println(conn-1);
    }
}


import java.io.*;
import java.util.*;
public class A277
{
    public static void main(String args[])throws IOException
    {
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        String s[]=br.readLine().trim().split(" ");
        int n=Integer.parseInt(s[0]);
        int m=Integer.parseInt(s[1]);
        HashMap<Integer,ArrayList<Integer>> emp=new HashMap<>();
        HashMap<Integer,ArrayList<Integer>> lang=new HashMap<>();
        HashMap<Integer,ArrayList<Integer>> map=new HashMap<>();
        int id[]=new int[n+1];

        for(int i=1;i<=m;i++)
        {
            lang.put(i,new ArrayList<Integer>());
            //map.put(i,new ArrayList<Integer>());
        }
        int c=0;
        for(int i=1;i<=n;i++)
        {
            emp.put(i,new ArrayList<Integer>());
            map.put(i,new ArrayList<Integer>());
            s=br.readLine().trim().split(" ");
            int k=Integer.parseInt(s[0]);
            if(k!=0)
            {
                for(int j=1;j<=k;j++)
                {
                    emp.get(i).add(Integer.parseInt(s[j]));
                    lang.get(Integer.parseInt(s[j])).add(i);
                }
            }
            else
                c++;
        }
        //System.out.println(emp+" "+lang);
        int arr[][]=new int[n+1][m+1];
        for(int i:emp.keySet())
        {
            //map.put(i,new ArrayList<Integer>());
            List<Integer> list=emp.get(i);
            for(int j:list)
            {

                for(int k:lang.get(j))
                {
                    if(arr[k][j]==0)
                    {
                        if(i!=k)
                        {
                            map.get(i).add(k);
                            map.get(k).add(i);
                        }
                        arr[k][j]=1;
                    }
                }
            }
            //System.out.println(map);
        }
        //System.out.println(map);
        boolean visit[]=new boolean[n+1];int conn=0;
        for(int i=1;i<=n;i++)
        {
            if(!visit[i])
            {
                conn++;
                visit[i]=true;
                Stack st=new Stack();
                st.push(i);
                while(st.size()!=0)
                {
                    int a=(Integer)st.pop();
                    for(int j:map.get(a))
                    {
                        if(!visit[j])
                        {
                            visit[j]=true;
                            st.push(j);

                        }
                    }
                }
            }
        }
        if(c==n)
            System.out.println(c);
        else
            System.out.println(conn-1);
    }
}


import java.io.*;
import java.util.*;
public class A277
{
    public static void main(String args[])throws IOException
    {
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        String s[]=br.readLine().trim().split(" ");
        int n=Integer.parseInt(s[0]);
        int m=Integer.parseInt(s[1]);
        HashMap<Integer,ArrayList<Integer>> emp=new HashMap<>();
        HashMap<Integer,ArrayList<Integer>> lang=new HashMap<>();
        HashMap<Integer,ArrayList<Integer>> map=new HashMap<>();
        int id[]=new int[n+1];

        for(int i=1;i<=m;i++)
        {
            lang.put(i,new ArrayList<Integer>());
            //map.put(i,new ArrayList<Integer>());
        }
        for(int i=1;i<=n;i++)
        {
            emp.put(i,new ArrayList<Integer>());
            map.put(i,new ArrayList<Integer>());
            s=br.readLine().trim().split(" ");
            int k=Integer.parseInt(s[0]);
            if(k!=0)
            {
                for(int j=1;j<=k;j++)
                {
                    emp.get(i).add(Integer.parseInt(s[j]));
                    lang.get(Integer.parseInt(s[j])).add(i);
                }
            }
        }
        //System.out.println(emp+" "+lang);
        int arr[][]=new int[n+1][m+1];
        for(int i:emp.keySet())
        {
            //map.put(i,new ArrayList<Integer>());
            List<Integer> list=emp.get(i);
            for(int j:list)
            {

                for(int k:lang.get(j))
                {
                    if(arr[k][j]==0)
                    {
                        if(i!=k)
                        {
                            map.get(i).add(k);
                            map.get(k).add(i);
                        }
                        arr[k][j]=1;
                    }
                }
            }
            //System.out.println(map);
        }
        //System.out.println(map);
        boolean visit[]=new boolean[n+1];int conn=0;
        for(int i=1;i<=m;i++)
        {
            if(!visit[i])
            {
                conn++;
                visit[i]=true;
                Stack st=new Stack();
                st.push(i);
                while(st.size()!=0)
                {
                    int a=(Integer)st.pop();
                    for(int j:map.get(a))
                    {
                        if(!visit[j])
                        {
                            visit[j]=true;
                            st.push(j);

                        }
                    }
                }
            }
        }
        System.out.println(conn-1);
    }
}


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

public class Main{
  /*
  .
  .
  .
  .
  .
  .
  .
  some constants
  .
  */
  static boolean visited[];
  static ArrayList<Integer> list[];
  static void dfs(int current){
    visited[current]=true;
    Iterator itr=list[current].listIterator();
    int temp;
    while(itr.hasNext()){
      temp=(int)itr.next();
      if(!visited[temp])
        dfs(temp);
    }
  }
  /*
  .
  .
  .
  if any
  .
  .
  */
  public static void main(String[] args) throws IOException{
		/*
		.
		.
		.
		.
		.
		.
		*/
    int n=ni();
    int m=ni();
    int i,j,k,l;
    boolean lang[][]=new boolean[n+1][m+1];
    list=new ArrayList[n+1];
    for(i=0;i<=n;i++){
      list[i]=new ArrayList<>();
    }
    int temp;
    for(i=1;i<=n;i++){
      temp=ni();
      for(j=1;j<=temp;j++){
        lang[i][ni()]=true;
        lang[i][0]=true;
      }
    }
    for(i=1;i<=n;i++){
      for(j=1;j<=m;j++){
        if(lang[i][j]){
          for(k=i+1;k<=n;k++){
            if(lang[k][j]){
              list[i].add(k);
              list[k].add(i);
            }
          }
        }
      }
    }
    /*
    for(i=1;i<=n;i++){
      sop(list[i]);
    }
    */
    int count=0;
    j=1;
    visited=new boolean[n+1];
    for(i=1;i<=n;i++){
      if(!visited[i]){
        dfs(i);
        count++;
      }
    }
    boolean flag=false;
    for(i=1;i<=n;i++){
      flag |= lang[i][0];
    }
    if(!flag)
      count++;
    sop(count-1);

    /*
		.
		.
		.
		.
		.
		.
		.
		*/
	}
	/*
	temporary functions
	.
	.
	*/
	/*
	fuctions
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	abcdefghijklmnopqrstuvwxyz
	.
	.
	.
	.
	.
	.
	*/
	static int modulo(int j,int m){
		if(j<0)
			return m+j;
		  if(j>=m)
			return j-m;

			return j;
	}
	static final int mod=1000000007;
	static final double eps=1e-8;
	static final long inf=100000000000000000L;
	static final boolean debug=true;
	static Reader in=new Reader();
	static StringBuilder ansa=new StringBuilder();
	static long powm(long a,long b,long m){
		long an=1;
		long c=a;
		while(b>0){
			if(b%2==1)
				an=(an*c)%m;
			c=(c*c)%m;
			b>>=1;
		}
		return an;
	}
	static Random rn=new Random();
	static void sop(Object a){System.out.println(a);}
	static int ni(){return in.nextInt();}
	static int[] nia(int n){int a[]=new int[n];for(int i=0;i<n;i++)a[i]=ni();return a;}
	static long nl(){return in.nextLong();}
	static long[] nla(int n){long a[]=new long[n];for(int i=0; i<n; i++)a[i]=nl();return a;}
	static String ns(){return in.next();}
	static String[] nsa(int n){String a[]=new String[n];for(int i=0; i<n; i++)a[i]=ns();return a;}
	static double nd(){return in.nextDouble();}
	static double[] nda(int n){double a[]=new double[n];for(int i=0;i<n;i++)a[i]=nd();return a;}
	static class Reader{
		public BufferedReader reader;
		public StringTokenizer tokenizer;
		public Reader(){
			reader=new BufferedReader(new InputStreamReader(System.in),32768);
			tokenizer=null;
		}
		public String next(){
			while(tokenizer==null || !tokenizer.hasMoreTokens()){
				try{
					tokenizer=new StringTokenizer(reader.readLine());
				}
				catch(IOException e){
					throw new RuntimeException(e);
				}
			}
			return tokenizer.nextToken();
		}
		public int nextInt(){
			return Integer.parseInt(next());
		}
		public long nextLong(){
			return Long.parseLong(next());
		}
		public double nextDouble(){
			return Double.parseDouble(next());
		}
	}
}


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

public class Main{
  /*
  .
  .
  .
  .
  .
  .
  .
  some constants
  .
  */
  static boolean visited[];
  static ArrayList<Integer> list[];
  static void dfs(int current){
    visited[current]=true;
    Iterator itr=list[current].listIterator();
    int temp;
    while(itr.hasNext()){
      temp=(int)itr.next();
      if(!visited[temp])
        dfs(temp);
    }
  }
  /*
  .
  .
  .
  if any
  .
  .
  */
  public static void main(String[] args) throws IOException{
		/*
		.
		.
		.
		.
		.
		.
		*/
    int n=ni();
    int m=ni();
    int i,j,k,l;
    boolean lang[][]=new boolean[n+1][m+1];
    list=new ArrayList[n+1];
    for(i=0;i<=n;i++){
      list[i]=new ArrayList<>();
    }
    int temp;
    for(i=1;i<=n;i++){
      temp=ni();
      for(j=1;j<=temp;j++){
        lang[i][ni()]=true;
      }
    }
    for(i=1;i<=n;i++){
      for(j=1;j<=m;j++){
        if(lang[i][j]){
          for(k=i+1;k<=n;k++){
            if(lang[k][j]){
              list[i].add(k);
              list[k].add(i);
            }
          }
        }
      }
    }
    /*
    for(i=1;i<=n;i++){
      sop(list[i]);
    }
    */
    int count=0;
    j=1;
    visited=new boolean[n+1];
    for(i=1;i<=n;i++){
      if(list[i].size()==0){
        j++;
      }
    }
    if(j==(n+1)){
      count++;
    }
    for(i=1;i<=n;i++){
      if(!visited[i]){
        dfs(i);
        count++;
      }
    }
    sop(count-1);
    /*
		.
		.
		.
		.
		.
		.
		.
		*/
	}
	/*
	temporary functions
	.
	.
	*/
	/*
	fuctions
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	abcdefghijklmnopqrstuvwxyz
	.
	.
	.
	.
	.
	.
	*/
	static int modulo(int j,int m){
		if(j<0)
			return m+j;
		  if(j>=m)
			return j-m;

			return j;
	}
	static final int mod=1000000007;
	static final double eps=1e-8;
	static final long inf=100000000000000000L;
	static final boolean debug=true;
	static Reader in=new Reader();
	static StringBuilder ansa=new StringBuilder();
	static long powm(long a,long b,long m){
		long an=1;
		long c=a;
		while(b>0){
			if(b%2==1)
				an=(an*c)%m;
			c=(c*c)%m;
			b>>=1;
		}
		return an;
	}
	static Random rn=new Random();
	static void sop(Object a){System.out.println(a);}
	static int ni(){return in.nextInt();}
	static int[] nia(int n){int a[]=new int[n];for(int i=0;i<n;i++)a[i]=ni();return a;}
	static long nl(){return in.nextLong();}
	static long[] nla(int n){long a[]=new long[n];for(int i=0; i<n; i++)a[i]=nl();return a;}
	static String ns(){return in.next();}
	static String[] nsa(int n){String a[]=new String[n];for(int i=0; i<n; i++)a[i]=ns();return a;}
	static double nd(){return in.nextDouble();}
	static double[] nda(int n){double a[]=new double[n];for(int i=0;i<n;i++)a[i]=nd();return a;}
	static class Reader{
		public BufferedReader reader;
		public StringTokenizer tokenizer;
		public Reader(){
			reader=new BufferedReader(new InputStreamReader(System.in),32768);
			tokenizer=null;
		}
		public String next(){
			while(tokenizer==null || !tokenizer.hasMoreTokens()){
				try{
					tokenizer=new StringTokenizer(reader.readLine());
				}
				catch(IOException e){
					throw new RuntimeException(e);
				}
			}
			return tokenizer.nextToken();
		}
		public int nextInt(){
			return Integer.parseInt(next());
		}
		public long nextLong(){
			return Long.parseLong(next());
		}
		public double nextDouble(){
			return Double.parseDouble(next());
		}
	}
}


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

public class Main{
  /*
  .
  .
  .
  .
  .
  .
  .
  some constants
  .
  */
  static boolean visited[];
  static ArrayList<Integer> list[];
  static void dfs(int current){
    visited[current]=true;
    Iterator itr=list[current].listIterator();
    int temp;
    while(itr.hasNext()){
      temp=(int)itr.next();
      if(!visited[temp])
        dfs(temp);
    }
  }
  /*
  .
  .
  .
  if any
  .
  .
  */
  public static void main(String[] args) throws IOException{
		/*
		.
		.
		.
		.
		.
		.
		*/
    int n=ni();
    int m=ni();
    int i,j,k,l;
    boolean lang[][]=new boolean[n+1][m+1];
    list=new ArrayList[n+1];
    for(i=0;i<=n;i++){
      list[i]=new ArrayList<>();
    }
    int temp;
    for(i=1;i<=n;i++){
      temp=ni();
      for(j=1;j<=temp;j++){
        lang[i][ni()]=true;
      }
    }
    for(i=1;i<=n;i++){
      for(j=1;j<=m;j++){
        if(lang[i][j]){
          for(k=i+1;k<=n;k++){
            if(lang[k][j]){
              list[i].add(k);
              list[k].add(i);
            }
          }
        }
      }
    }
    /*
    for(i=1;i<=n;i++){
      sop(list[i]);
    }
    */
    int count=0;
    visited=new boolean[n+1];
    for(i=1;i<=n;i++){
      if(!visited[i]){
        dfs(i);
        count++;
      }
    }
    sop(count-1);
    /*
		.
		.
		.
		.
		.
		.
		.
		*/
	}
	/*
	temporary functions
	.
	.
	*/
	/*
	fuctions
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	abcdefghijklmnopqrstuvwxyz
	.
	.
	.
	.
	.
	.
	*/
	static int modulo(int j,int m){
		if(j<0)
			return m+j;
		  if(j>=m)
			return j-m;

			return j;
	}
	static final int mod=1000000007;
	static final double eps=1e-8;
	static final long inf=100000000000000000L;
	static final boolean debug=true;
	static Reader in=new Reader();
	static StringBuilder ansa=new StringBuilder();
	static long powm(long a,long b,long m){
		long an=1;
		long c=a;
		while(b>0){
			if(b%2==1)
				an=(an*c)%m;
			c=(c*c)%m;
			b>>=1;
		}
		return an;
	}
	static Random rn=new Random();
	static void sop(Object a){System.out.println(a);}
	static int ni(){return in.nextInt();}
	static int[] nia(int n){int a[]=new int[n];for(int i=0;i<n;i++)a[i]=ni();return a;}
	static long nl(){return in.nextLong();}
	static long[] nla(int n){long a[]=new long[n];for(int i=0; i<n; i++)a[i]=nl();return a;}
	static String ns(){return in.next();}
	static String[] nsa(int n){String a[]=new String[n];for(int i=0; i<n; i++)a[i]=ns();return a;}
	static double nd(){return in.nextDouble();}
	static double[] nda(int n){double a[]=new double[n];for(int i=0;i<n;i++)a[i]=nd();return a;}
	static class Reader{
		public BufferedReader reader;
		public StringTokenizer tokenizer;
		public Reader(){
			reader=new BufferedReader(new InputStreamReader(System.in),32768);
			tokenizer=null;
		}
		public String next(){
			while(tokenizer==null || !tokenizer.hasMoreTokens()){
				try{
					tokenizer=new StringTokenizer(reader.readLine());
				}
				catch(IOException e){
					throw new RuntimeException(e);
				}
			}
			return tokenizer.nextToken();
		}
		public int nextInt(){
			return Integer.parseInt(next());
		}
		public long nextLong(){
			return Long.parseLong(next());
		}
		public double nextDouble(){
			return Double.parseDouble(next());
		}
	}
}


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

public class Main{
  /*
  .
  .
  .
  .
  .
  .
  .
  some constants
  .
  */
  static boolean visited[];
  static ArrayList<Integer> list[];
  static void dfs(int current){
    visited[current]=true;
    Iterator itr=list[current].listIterator();
    int temp;
    while(itr.hasNext()){
      temp=(int)itr.next();
      if(!visited[temp])
        dfs(temp);
    }
  }
  /*
  .
  .
  .
  if any
  .
  .
  */
  public static void main(String[] args) throws IOException{
		/*
		.
		.
		.
		.
		.
		.
		*/
    int n=ni();
    int m=ni();
    int i,j,k,l;
    boolean lang[][]=new boolean[n+1][m+1];
    list=new ArrayList[n+1];
    for(i=0;i<=n;i++){
      list[i]=new ArrayList<>();
    }
    int temp;
    for(i=1;i<=n;i++){
      temp=ni();
      for(j=1;j<=temp;j++){
        lang[i][ni()]=true;
        lang[i][0]=true;
      }
    }
    for(i=1;i<=n;i++){
      for(j=1;j<=m;j++){
        if(lang[i][j]){
          for(k=i+1;k<=n;k++){
            if(lang[k][j]){
              list[i].add(k);
              list[k].add(i);
            }
          }
        }
      }
    }
    /*
    for(i=1;i<=n;i++){
      sop(list[i]);
    }
    */
    int count=0;
    j=1;
    visited=new boolean[n+1];
    for(i=1;i<=n;i++){
      if(!visited[i]){
        dfs(i);
        count++;
      }
    }
    for(i=1;i<=n;i++){
      if(!lang[i][0]){
        //sop(lang[i][0]);
        break;
      }
    }
    //sop(i+" "+(n+1));
    if(i!=(n+1))
      count++;
    sop(count-1);

    /*
		.
		.
		.
		.
		.
		.
		.
		*/
	}
	/*
	temporary functions
	.
	.
	*/
	/*
	fuctions
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	abcdefghijklmnopqrstuvwxyz
	.
	.
	.
	.
	.
	.
	*/
	static int modulo(int j,int m){
		if(j<0)
			return m+j;
		  if(j>=m)
			return j-m;

			return j;
	}
	static final int mod=1000000007;
	static final double eps=1e-8;
	static final long inf=100000000000000000L;
	static final boolean debug=true;
	static Reader in=new Reader();
	static StringBuilder ansa=new StringBuilder();
	static long powm(long a,long b,long m){
		long an=1;
		long c=a;
		while(b>0){
			if(b%2==1)
				an=(an*c)%m;
			c=(c*c)%m;
			b>>=1;
		}
		return an;
	}
	static Random rn=new Random();
	static void sop(Object a){System.out.println(a);}
	static int ni(){return in.nextInt();}
	static int[] nia(int n){int a[]=new int[n];for(int i=0;i<n;i++)a[i]=ni();return a;}
	static long nl(){return in.nextLong();}
	static long[] nla(int n){long a[]=new long[n];for(int i=0; i<n; i++)a[i]=nl();return a;}
	static String ns(){return in.next();}
	static String[] nsa(int n){String a[]=new String[n];for(int i=0; i<n; i++)a[i]=ns();return a;}
	static double nd(){return in.nextDouble();}
	static double[] nda(int n){double a[]=new double[n];for(int i=0;i<n;i++)a[i]=nd();return a;}
	static class Reader{
		public BufferedReader reader;
		public StringTokenizer tokenizer;
		public Reader(){
			reader=new BufferedReader(new InputStreamReader(System.in),32768);
			tokenizer=null;
		}
		public String next(){
			while(tokenizer==null || !tokenizer.hasMoreTokens()){
				try{
					tokenizer=new StringTokenizer(reader.readLine());
				}
				catch(IOException e){
					throw new RuntimeException(e);
				}
			}
			return tokenizer.nextToken();
		}
		public int nextInt(){
			return Integer.parseInt(next());
		}
		public long nextLong(){
			return Long.parseLong(next());
		}
		public double nextDouble(){
			return Double.parseDouble(next());
		}
	}
}


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

public class Main{
  /*
  .
  .
  .
  .
  .
  .
  .
  some constants
  .
  */
  static boolean visited[];
  static ArrayList<Integer> list[];
  static void dfs(int current){
    visited[current]=true;
    Iterator itr=list[current].listIterator();
    int temp;
    while(itr.hasNext()){
      temp=(int)itr.next();
      if(!visited[temp])
        dfs(temp);
    }
  }
  /*
  .
  .
  .
  if any
  .
  .
  */
  public static void main(String[] args) throws IOException{
		/*
		.
		.
		.
		.
		.
		.
		*/
    int n=ni();
    int m=ni();
    int i,j,k,l;
    boolean lang[][]=new boolean[n+1][m+1];
    list=new ArrayList[n+1];
    for(i=0;i<=n;i++){
      list[i]=new ArrayList<>();
    }
    int temp;
    for(i=1;i<=n;i++){
      temp=ni();
      for(j=1;j<=temp;j++){
        lang[i][ni()]=true;
        lang[i][0]=true;
      }
    }
    for(i=1;i<=n;i++){
      for(j=1;j<=m;j++){
        if(lang[i][j]){
          for(k=i+1;k<=n;k++){
            if(lang[k][j]){
              list[i].add(k);
              list[k].add(i);
            }
          }
        }
      }
    }
    /*
    for(i=1;i<=n;i++){
      sop(list[i]);
    }
    */
    int count=0;
    j=1;
    visited=new boolean[n+1];
    for(i=1;i<=n;i++){
      if(!visited[i]){
        dfs(i);
        count++;
      }
    }
    for(i=1;i<=n;i++){
      if(!lang[i][0])
        break;
    }
    if(i==(n+1))
      count++;
    sop(count-1);

    /*
		.
		.
		.
		.
		.
		.
		.
		*/
	}
	/*
	temporary functions
	.
	.
	*/
	/*
	fuctions
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	.
	abcdefghijklmnopqrstuvwxyz
	.
	.
	.
	.
	.
	.
	*/
	static int modulo(int j,int m){
		if(j<0)
			return m+j;
		  if(j>=m)
			return j-m;

			return j;
	}
	static final int mod=1000000007;
	static final double eps=1e-8;
	static final long inf=100000000000000000L;
	static final boolean debug=true;
	static Reader in=new Reader();
	static StringBuilder ansa=new StringBuilder();
	static long powm(long a,long b,long m){
		long an=1;
		long c=a;
		while(b>0){
			if(b%2==1)
				an=(an*c)%m;
			c=(c*c)%m;
			b>>=1;
		}
		return an;
	}
	static Random rn=new Random();
	static void sop(Object a){System.out.println(a);}
	static int ni(){return in.nextInt();}
	static int[] nia(int n){int a[]=new int[n];for(int i=0;i<n;i++)a[i]=ni();return a;}
	static long nl(){return in.nextLong();}
	static long[] nla(int n){long a[]=new long[n];for(int i=0; i<n; i++)a[i]=nl();return a;}
	static String ns(){return in.next();}
	static String[] nsa(int n){String a[]=new String[n];for(int i=0; i<n; i++)a[i]=ns();return a;}
	static double nd(){return in.nextDouble();}
	static double[] nda(int n){double a[]=new double[n];for(int i=0;i<n;i++)a[i]=nd();return a;}
	static class Reader{
		public BufferedReader reader;
		public StringTokenizer tokenizer;
		public Reader(){
			reader=new BufferedReader(new InputStreamReader(System.in),32768);
			tokenizer=null;
		}
		public String next(){
			while(tokenizer==null || !tokenizer.hasMoreTokens()){
				try{
					tokenizer=new StringTokenizer(reader.readLine());
				}
				catch(IOException e){
					throw new RuntimeException(e);
				}
			}
			return tokenizer.nextToken();
		}
		public int nextInt(){
			return Integer.parseInt(next());
		}
		public long nextLong(){
			return Long.parseLong(next());
		}
		public double nextDouble(){
			return Double.parseDouble(next());
		}
	}
}


import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.*;

/**
 * @author pvasilyev
 * @since 30 Mar 2017
 */
public class A277 {

    public static void main(String[] args) throws IOException {
        final Scanner reader = new Scanner(new InputStreamReader(System.in));
        final PrintWriter writer = new PrintWriter(System.out);

        solve(reader, writer);

        writer.close();
        reader.close();
    }

    private static void solve(final Scanner reader, final PrintWriter writer) {
        final int n = reader.nextInt();
        final int m = reader.nextInt();

        final HashMap<Integer, List<Integer>> g = new HashMap<>();
        for (int i = 1; i <= n; ++i) {
            g.put(i, new ArrayList<>());
            final int mi = reader.nextInt();
            for (int j = 1; j <= mi; ++j) {
                final int lang = reader.nextInt();
                g.get(i).add(-lang);
                if (!g.containsKey(-lang)) {
                    g.put(-lang, new ArrayList<>());
                }
                g.get(-lang).add(i);
            }
        }

        final HashSet<Integer> visited = new HashSet<>();
        final HashMap<Integer, List<Integer>> ccs = new HashMap<>();
        int c = 0;
        for (int i = 1; i <= n; ++i) {
            if (!visited.contains(i)) {
                c++;
                dfs(visited, g, i, ccs, c);
            }
        }
        int nullable = 0;
        for (Map.Entry<Integer, List<Integer>> integerListEntry : ccs.entrySet()) {
            if (integerListEntry.getValue().size() == 1) {
                nullable++;
            }
        }
        final int nonNullable = ccs.size() - nullable;
        writer.println(nullable + (nonNullable == 0 ? nonNullable : nonNullable - 1));
    }

    private static void dfs(final HashSet<Integer> visited, final HashMap<Integer, List<Integer>> g,
                            final int start, final HashMap<Integer, List<Integer>> ccs, final int c) {
        visited.add(start);
        if (!ccs.containsKey(c)) {
            ccs.put(c, new ArrayList<>());
        }
        //if (start > 0) {
            ccs.get(c).add(start);
        //}
        for (Integer outbound : g.get(start)) {
            if (!visited.contains(outbound)) {
                dfs(visited, g, outbound, ccs, c);
            }
        }
    }

}


import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.*;

/**
 * @author pvasilyev
 * @since 30 Mar 2017
 */
public class A277 {

    public static void main(String[] args) throws IOException {
        final Scanner reader = new Scanner(new InputStreamReader(System.in));
        final PrintWriter writer = new PrintWriter(System.out);

        solve(reader, writer);

        writer.close();
        reader.close();
    }

    private static void solve(final Scanner reader, final PrintWriter writer) {
        final int n = reader.nextInt();
        final int m = reader.nextInt();

        final DSU dsu = new DSU(n + m);
        for (int i = 1; i <= n + m; ++i) {
            dsu.makeSet(i);
        }

        for (int i = 1; i <= n; ++i) {
            int k = reader.nextInt();
            for (int j = 0; j < k; ++j) {
                int lang = reader.nextInt() + n;
                dsu.union(i, lang);
            }
        }

        Set<Integer> set = new HashSet<>();
        for (int i = 1; i <= n; ++i) {
            set.add(dsu.findSet(i));
        }
        writer.println(set.size() - 1);
    }

    private static class DSU {
        private int[] p;

        private DSU(int n) {
            p = new int[n + 1];
        }

        private void makeSet(int u) {
            p[u] = u;
        }

        private int findSet(int u) {
            if (p[u] == u) return u;
            int parent = findSet(p[u]);
            p[u] = parent;
            return parent;
        }

        private void union(int u, int v) {
            int a = findSet(u);
            int b = findSet(v);

            if (a != b) {
                if (b < a) {
                    int t = a;
                    a = b;
                    b = t;
                }
                p[b] = a;
            }
        }
    }

}


import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.*;

/**
 * @author pvasilyev
 * @since 30 Mar 2017
 */
public class A277 {

    public static void main(String[] args) throws IOException {
        final Scanner reader = new Scanner(new InputStreamReader(System.in));
        final PrintWriter writer = new PrintWriter(System.out);

        solve(reader, writer);

        writer.close();
        reader.close();
    }

    private static void solve(final Scanner reader, final PrintWriter writer) {
        final int n = reader.nextInt();
        final int m = reader.nextInt();

        final DSU dsu = new DSU(n + m);
        for (int i = 1; i <= n + m; ++i) {
            dsu.makeSet(i);
        }

        for (int i = 1; i <= n; ++i) {
            int k = reader.nextInt();
            for (int j = 0; j < k; ++j) {
                int lang = reader.nextInt() + n;
                dsu.union(i, lang);
            }
        }

        if (noOneKnowsNoLangs(dsu, n, m)) {
            writer.println(n);
        } else {
            Set<Integer> set = new HashSet<>();
            for (int i = 1; i <= n; ++i) {
                set.add(dsu.findSet(i));
            }
            writer.println(set.size() - 1);
        }
    }

    private static boolean noOneKnowsNoLangs(DSU dsu, int n, int m) {
        for (int i = n + 1; i <= n + m; ++i) {
            if (dsu.findSet(i) != i) {
                return false;
            }
        }
        return true;
    }

    private static class DSU {
        private int[] p;

        private DSU(int n) {
            p = new int[n + 1];
        }

        private void makeSet(int u) {
            p[u] = u;
        }

        private int findSet(int u) {
            if (p[u] == u) return u;
            int parent = findSet(p[u]);
            p[u] = parent;
            return parent;
        }

        private void union(int u, int v) {
            int a = findSet(u);
            int b = findSet(v);

            if (a != b) {
                if (b < a) {
                    int t = a;
                    a = b;
                    b = t;
                }
                p[b] = a;
            }
        }
    }

}


import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.*;

/**
 * @author pvasilyev
 * @since 30 Mar 2017
 */
public class A277 {

    public static void main(String[] args) throws IOException {
        final Scanner reader = new Scanner(new InputStreamReader(System.in));
        final PrintWriter writer = new PrintWriter(System.out);

        solve(reader, writer);

        writer.close();
        reader.close();
    }

    private static void solve(final Scanner reader, final PrintWriter writer) {
        final int n = reader.nextInt();
        final int m = reader.nextInt();

        final HashMap<Integer, List<Integer>> g = new HashMap<>();
        for (int i = 1; i <= n; ++i) {
            g.put(i, new ArrayList<>());
            final int mi = reader.nextInt();
            for (int j = 1; j <= mi; ++j) {
                final int lang = reader.nextInt();
                g.get(i).add(-lang);
                if (!g.containsKey(-lang)) {
                    g.put(-lang, new ArrayList<>());
                }
                g.get(-lang).add(i);
            }
        }

        final HashSet<Integer> visited = new HashSet<>();
        int c = 0;
        for (int i = 1; i <= n; ++i) {
            if (!visited.contains(i)) {
                c++;
                dfs(visited, g, i);
            }
        }
        writer.println(c-1);
    }

    private static void dfs(final HashSet<Integer> visited, final HashMap<Integer, List<Integer>> g, final int start) {
        visited.add(start);
        for (Integer outbound : g.get(start)) {
            if (!visited.contains(outbound)) {
                dfs(visited, g, outbound);
            }
        }
    }

}


import java.util.ArrayList;
import java.util.Scanner;
import java.util.TreeSet;

public class Learning_Languages {

	static boolean vis[];
	static ArrayList<Integer> []  adj;
	public static void dfs(int x) {
		vis[x]=true;
		for(int y:adj[x]) {
			if(!vis[y]) {
				dfs(y);
			}
		}
	}

   public static void main(String []  arga) {
	   Scanner sc=new Scanner (System.in);
	   int n=sc.nextInt();
	   int m=sc.nextInt();
	boolean flag=true;
	   vis=new boolean [n];
	   int cost=0;

	   TreeSet< Integer> [] tsarr=new TreeSet[n];
	    adj=new ArrayList [n];
	   for(int i=0;i<n;i++) {
		   tsarr[i]=new TreeSet<Integer>();
		   adj[i]=new ArrayList<Integer>();
	   }
	   for(int i=0;i<n;i++) {
		   int k=sc.nextInt();
		   if(k!=0) {
			   flag=false;
		   }
		   for(int j=0;j<k;j++) {
		      tsarr[i].add(sc.nextInt());

		 }
	   }

		   for(int i=0;i<n;i++) {
			 for(int x:tsarr[i]) {
				 for(int j=0;j<n;j++) {
					 if(j!=i) {
					 for(int y:tsarr[j]) {
						 if(y==x ) {
							 adj[i].add(j);
						 }

					 }
					 }
				 }
			 }

             }

//		   for(int i=0;i<n;i++) {
//			   for(int x:adj[i]) {
//				   System.out.print(x+" ");
//			   }
//			   System.out.println();

		 //  }
		   int c=-1;
		   for(int i=0;i<n;i++) {
			   if(!vis[i]) {
				 c++;

		        dfs(i);
		   }
		   }

	   if(!flag) {
	   System.out.println(c);
	   }
	   else {
		   System.out.println(n);
	   }
}
}


import java.util.ArrayList;
import java.util.Scanner;
import java.util.TreeSet;

public class Learning_Languages {

	static boolean vis[];
	static ArrayList<Integer> []  adj;
	public static void dfs(int x) {
		vis[x]=true;
		for(int y:adj[x]) {
			if(!vis[y]) {
				dfs(y);
			}
		}
	}

   public static void main(String []  arga) {
	   Scanner sc=new Scanner (System.in);
	   int n=sc.nextInt();
	   int m=sc.nextInt();
	boolean flag=true;
	   vis=new boolean [n];
	   int cost=0;

	   ArrayList<Integer> [] tsarr=new ArrayList[n];
	    adj=new ArrayList [n];
	   for(int i=0;i<n;i++) {
		   tsarr[i]=new ArrayList<Integer>();
		   adj[i]=new ArrayList<Integer>();
	   }
	   for(int i=0;i<n;i++) {
		   int k=sc.nextInt();
		   if(k!=0) {
			   flag=false;
		   }
		   for(int j=0;j<k;j++) {
		      tsarr[i].add(sc.nextInt());

		 }
	   }

		   for(int i=0;i<n;i++) {
			 for(int x:tsarr[i]) {
				 for(int j=0;j<n;j++) {
					 if(j!=i) {
					 for(int y:tsarr[j]) {
						 if(y==x ) {
							 adj[i].add(j);
						 }

					 }
					 }
				 }
			 }

             }

//		   for(int i=0;i<n;i++) {
//			   for(int x:adj[i]) {
//				   System.out.print(x+" ");
//			   }
//			   System.out.println();

		 //  }
		   int c=-1;
		   for(int i=0;i<n;i++) {
			   if(!vis[i]) {
				 c++;

		        dfs(i);
		   }
		   }

	   if(!flag) {
	   System.out.println(c);
	   }
	   else {
		   System.out.println(n);
	   }
}
}


import java.util.ArrayList;
import java.util.Scanner;
import java.util.TreeSet;

public class Learning_Languages {
	static boolean vis[];
	static ArrayList<Integer> []  adj;
	public static void dfs(int x) {
		vis[x]=true;
		for(int y:adj[x]) {
			if(!vis[y]) {
				dfs(y);
			}
		}
	}

   public static void main(String []  arga) {
	   Scanner sc=new Scanner (System.in);
	   int n=sc.nextInt();
	   int m=sc.nextInt();

	   vis=new boolean [n];
	   int cost=0;

	   TreeSet< Integer> [] tsarr=new TreeSet[n];
	    adj=new ArrayList [n];
	   for(int i=0;i<n;i++) {
		   tsarr[i]=new TreeSet<Integer>();
		   adj[i]=new ArrayList<Integer>();
	   }
	   for(int i=0;i<n;i++) {
		   int k=sc.nextInt();
		   for(int j=0;j<k;j++) {
		      tsarr[i].add(sc.nextInt());

		 }
	   }

		   for(int i=0;i<n;i++) {
			 for(int x:tsarr[i]) {
				 for(int j=0;j<n;j++) {
					 if(j!=i) {
					 for(int y:tsarr[j]) {
						 if(y==x ) {
							 adj[i].add(j);
						 }

					 }
					 }
				 }
			 }

             }

//		   for(int i=0;i<n;i++) {
//			   for(int x:adj[i]) {
//				   System.out.print(x+" ");
//			   }
//			   System.out.println();

		 //  }
		   int c=-1;
		   for(int i=0;i<n;i++) {
			   if(!vis[i]) {
				 c++;

		        dfs(i);
		   }
		   }

	   System.out.println(c);
}
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Set;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.StringTokenizer;
import java.util.Queue;
import java.io.BufferedReader;
import java.util.LinkedList;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) throws IOException {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        A170 solver = new A170();
        solver.solve(1, in, out);
        out.close();
    }

    static class A170 {
        int[][] graph;
        Set<Integer> set;
        Queue<Integer> q;

        public void solve(int testNumber, InputReader in, PrintWriter out) throws IOException {

            StringTokenizer st = new StringTokenizer(in.nextLine());
            int aris = Integer.parseInt(st.nextToken());
            int n = Integer.parseInt(st.nextToken());
            graph = new int[n][n];
            set = new HashSet<Integer>();
            q = new LinkedList<>();

            int count = 0;
            while (aris-- > 0) {

                st = new StringTokenizer(in.nextLine());
                int cur = Integer.parseInt(st.nextToken());
                if (cur == 0)
                    count++;
                else {
                    int aux = Integer.parseInt(st.nextToken()) - 1;

                    if (!set.contains(aux))
                        q.add(aux);
                    set.add(aux);
                    while (st.hasMoreTokens()) {
                        int act = Integer.parseInt(st.nextToken()) - 1;
                        graph[aux][act] = 1;
                        graph[act][aux] = 1;

                        aux = act;
                        if (!set.contains(act))
                            q.add(act);
                        set.add(act);
                    }
                }
            }

            while (!q.isEmpty()) {
                boolean[] visited = new boolean[n];
                dfs(q.peek(), visited);

                count++;
            }

            out.println(count - 1);

        }

        void dfs(int nod, boolean[] visited) {
            visited[nod] = true;
            q.poll();
            for (int i = 0; i < graph[nod].length; i++) {
                if (!visited[i] && graph[nod][i] == 1) {
                    dfs(i, visited);
                }
            }

        }

    }

    static class InputReader {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }

        public String nextLine() throws IOException {
            return reader.readLine();
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.StringTokenizer;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) throws IOException{
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        A170 solver = new A170();
        solver.solve(1, in, out);
        out.close();
    }

    static class A170 {
        int[][] graph = new int[102][102];
        boolean[] visited = new boolean[102];

        public void solve(int testNumber, InputReader in, PrintWriter out) throws IOException {

            StringTokenizer st = new StringTokenizer(in.nextLine());
            int aris = Integer.parseInt(st.nextToken());
            int n = Integer.parseInt(st.nextToken());
            int[] hash = new int[102];
            int count = 0;
            boolean enter = false;

            for (int i = 0; i < aris; i++) {

                String[] s = in.nextLine().split(" ");
                int cur = Integer.parseInt(s[0]);
                if (cur == 0) {
                    count++;
                } else {
                    enter = true;
                    int aux = Integer.parseInt(s[1]);
                    hash[aux]++;
                    for (int j = 1; j < cur; j++) {
                        int ac = Integer.parseInt(s[j + 1]);
                        hash[ac]++;
                        graph[aux][ac] = 1;
                        graph[ac][aux] = 1;
                        aux = ac;
                    }
                }

            }
            if (enter) {

                for (int i = 1; i <= aris; i++) {

                    if (!visited[i] && hash[i] > 0) {
                        dfs(i);
                        count++;
                    }

                }
                out.println(count - 1);
            } else
                out.println(aris);

        }

        void dfs(int nod) {
            visited[nod] = true;
            for (int i = 0; i < graph[nod].length; i++) {

                if (!visited[i] && graph[nod][i] == 1) {
                    dfs(i);
                }
            }

        }

    }

    static class InputReader {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }

        public String nextLine() throws IOException {
            return reader.readLine();
        }

    }
}