Problem:
 Score : 400 points    Problem Statement On a planet far, far away, M languages are spoken. They are conveniently numbered 1 through M .  For CODE FESTIVAL 20XX held on this planet, N participants gathered from all over the planet.  The i -th (1≦i≦N) participant can speak K_i languages numbered L_{i,1}, L_{i,2}, ..., L_{i,{}K_i} .  Two participants A and B can communicate with each other if and only if one of the following conditions is satisfied:   There exists a language that both A and B can speak.  There exists a participant X that both A and B can communicate with.   Determine whether all N participants can communicate with all other participants.      Constraints  2≦N≦10^5  1≦M≦10^5  1≦K_i≦M  ( The sum of all K_i)≦10^5  1≦L_{i,j}≦M  L_{i,1}, L_{i,2}, ..., L_{i,{}K_i} are pairwise distinct.       Partial Score  200 points will be awarded for passing the test set satisfying the following: N≦1000 , M≦1000 and ( The sum of all K_i)≦1000 .  Additional 200 points will be awarded for passing the test set without additional constraints.         Input The input is given from Standard Input in the following format:  N  M  K_1  L_{1,1}  L_{1,2}  ...  L_{1,{}K_1}  K_2  L_{2,1}  L_{2,2}  ...  L_{2,{}K_2}  :  K_N  L_{N,1}  L_{N,2}  ...  L_{N,{}K_N}       Output If all N participants can communicate with all other participants, print YES . Otherwise, print NO .        Sample Input 1 4 6
3 1 2 3
2 4 2
2 4 6
1 6      Sample Output 1 YES  Any two participants can communicate with each other, as follows:   Participants 1 and 2 : both can speak language 2 .  Participants 2 and 3 : both can speak language 4 .  Participants 1 and 3 : both can communicate with participant 2 .  Participants 3 and 4 : both can speak language 6 .  Participants 2 and 4 : both can communicate with participant 3 .  Participants 1 and 4 : both can communicate with participant 2 .   Note that there can be languages spoken by no participant.       Sample Input 2 4 4
2 1 2
2 1 2
1 3
2 4 3      Sample Output 2 NO  For example, participants 1 and 3 cannot communicate with each other.

Solution (Python):

import sys
try: from typing import Any, Union, List, Tuple, Dict
except ImportError: pass
sys.setrecursionlimit(10**6)
def debug(*args): print(*args, file=sys.stderr)
def exit(): sys.exit(0)


class UnionFind:
    def __init__(self, N):
        
        self.N = N
        self.parent = list(range(N))  

    def root(self, x):
        
        path_to_root = []
        while self.parent[x] != x:
            path_to_root.append(x)
            x = self.parent[x]
        for node in path_to_root:
            self.parent[node] = x  
        return x

    def same(self, x, y):
        
        return self.root(x) == self.root(y)

    def unite(self, x, y):
        
        self.parent[self.root(x)] = self.root(y)

    def __str__(self):
        
        groups = {}  
        for x in range(self.N):
            root = self.root(x)
            if root in groups.keys():
                groups[root].append(x)
            else:
                groups[root] = [x]
        result = ""
        for root in groups.keys():
            result += str(groups[root]) + "\n"
        return result

    def __len__(self):
        
        roots = list(map(lambda x: self.root(x),
                         range(self.N)))
        return len(set(roots))


N, M = map(int, input().split())
K = []
L = []
for i in range(N):
    temp = list(map(int, input().split()))
    K.append(temp[0])
    L.append(list(map(lambda x: x-1,
                      temp[1:])))


speaker = [[] for i in range(M)]  


for i in range(N):
    for k in range(K[i]):
        speaker[L[i][k]].append(i)

u = UnionFind(N)
for l in range(M):
    sp = speaker[l]
    if len(sp) > 0:
        for i in range(1, len(sp)):
            u.unite(sp[0], sp[i])
if len(u) == 1:
    print("YES")
else:
    print("NO")

Solution (Python):
N, M = map(int, input().split())
parent = [i for i in range(N + M)]
rank = [1] * (N + M)
def find(x):
    if x == parent[x]:
        return x
    parent[x] = find(parent[x])
    return parent[x]

def unite(x, y):
    x, y = find(x), find(y)
    if x == y:
        return
    if rank[x] == rank[y]:
        rank[x] += 1
    elif rank[x] < rank[y]:
        x, y = y, x
    parent[y] = x
for i in range(N):
    for l in list(map(int, input().split()))[1:]:
        
        unite(i, N + l - 1)
if all(find(0) == find(i) for i in range(N)):
    print('YES')
else:
    print('NO')

Solution (Python):
import sys
sys.setrecursionlimit(10 ** 7)

class UnionFind():
	def __init__(self, size):
		self.table = [-1 for _ in range(size)]

	def find(self, x):
		if self.table[x] < 0:
			return x
		else:
			self.table[x] = self.find(self.table[x])
			return self.table[x]

	def union(self, x, y):
		s1 = self.find(x)
		s2 = self.find(y)
		if s1 != s2:
			if self.table[s1] > self.table[s2]:
				self.table[s2] = s1
			elif self.table[s1] < self.table[s2]:
				self.table[s1] = s2
			else:
				self.table[s1] = s2
				self.table[s2] -= 1
		return

n, m = map(int, input().split())
lang = [[] for _ in range(m)]
for i in range(n):
	kl = list(map(int, input().split()))
	for j in range(1, kl[0] + 1):
		lang[kl[j] - 1].append(i)

uf = UnionFind(n)
for i in range(m):
	if len(lang[i]) <= 1:
		continue
	else:
		for j in range(len(lang[i]) - 1):
			uf.union(lang[i][j], lang[i][j + 1])

root_count = 0
for i in range(n):
	if uf.table[i] < 0:
		root_count += 1

if root_count == 1:
	print("YES")
else:
	print("NO")

Solution (Python):
import sys
sys.setrecursionlimit(10 ** 7)

class UnionFind():
	def __init__(self, size):
		self.table = [-1 for _ in range(size)]

	def find(self, x):
		if self.table[x] < 0:
			return x
		else:
			self.table[x] = self.find(self.table[x])
			return self.table[x]

	def union(self, x, y):
		s1 = self.find(x)
		s2 = self.find(y)
		if s1 != s2:
			if self.table[s1] > self.table[s2]:
				self.table[s2] = s1
			elif self.table[s1] < self.table[s2]:
				self.table[s1] = s2
			else:
				self.table[s1] = s2
				self.table[s2] -= 1
		return

n, m = map(int, input().split())
lang = [[] for _ in range(m)]
for i in range(n):
	kl = list(map(int, input().split()))
	for j in range(1, kl[0] + 1):
		lang[kl[j] - 1].append(i)

uf = UnionFind(n)
for i in range(m):
	if len(lang[i]) <= 1:
		continue
	else:
		for j in range(len(lang[i]) - 1):
			uf.union(lang[i][j], lang[i][j + 1])

root_count = 0
for i in range(n):
	if uf.table[i] < 0:
		root_count += 1

if root_count == 1:
	print("YES")
else:
	print("NO")

Solution (Python):

import sys
stdin = sys.stdin

def li(): return [int(x) for x in stdin.readline().split()]
def li_(): return [int(x)-1 for x in stdin.readline().split()]
def lf(): return [float(x) for x in stdin.readline().split()]
def ls(): return stdin.readline().split()
def ns(): return stdin.readline().rstrip()
def lc(): return list(ns())
def ni(): return int(ns())
def nf(): return float(ns())

class UnionFind:
    def __init__(self, node:int) -> None:
        self.n = node
        self.par = [i for i in range(self.n)]
        self.rank = [0 for i in range(self.n)]
        
    def find(self, x:int) -> int:
        if x == self.par[x]:
            return x
        else:
            self.par[x] = self.find(self.par[x])
            return self.par[x]
        
    def unite(self, x:int, y:int) -> bool:
        if self.isSame(x,y):
            
            return False
        
        rx = self.find(x)
        ry = self.find(y)
        
        if self.rank[rx] < self.rank[ry]:
            self.par[rx] = self.par[ry]
        else:
            self.par[ry] = self.par[rx]
            
            if self.rank[rx] == self.rank[ry]:
                self.rank[rx] += 1
                
        return True
                
    def isSame(self, x:int, y:int) -> bool:
        return self.find(x) == self.find(y)

from collections import defaultdict

dic = defaultdict(list)

n,m = li()


for i in range(n):
    l_list = li()
    for l in l_list[1:]:
        dic[l].append(i)
        

uf = UnionFind(n)
for key in dic.keys():
    val = dic[key]
    for i in range(len(val)-1):
        if not uf.isSame(val[i], val[i+1]):
            uf.unite(val[i], val[i+1])
            
root = uf.find(0)
for i in range(n):
    if uf.find(i) != root:
        print("NO")
        break
    
    if i == n-1:
        print("YES")

Solution (Python):
from collections import defaultdict,deque
import sys,heapq,bisect,math,itertools,string,queue,datetime
sys.setrecursionlimit(10**8)
INF = float('inf')
mod = 10**9+7
eps = 10**-7
def inp(): return int(input())
def inpl(): return list(map(int, input().split()))
def inpls(): return list(input().split())

def Find(x):	
	global table

	if table[x] == x:
		return x
	else:
		table[x] = Find(table[x])	
		return table[x]

def Unite(x,y):	
	x = Find(x)
	y = Find(y)

	if x == y:
		return

	if rank[x] > rank[y]:
		table[y] = x
	else:
		table[x] = y
		if rank[x] == rank[y]:
			rank[y] += 1

def Check(x,y):
	if Find(x) == Find(y):
		return True
	else:
		return False

N,M = inpl()

table = [i for i in range(N+M)]	
rank  = [1 for i in range(N+M)]	

for i in range(N):
	tmp = inpl()
	for k in range(tmp[0]):
		l = tmp[k+1]
		Unite(i,l+N-1)

tmp = Find(0)
for i in range(N):
	if tmp != Find(i):
		print('NO')
		sys.exit()
print('YES')

Solution (Python):
class UnionFind():
    def __init__(self,size):
        self.table = [-1 for _  in range(size)]

    def find(self,x):
        while self.table[x] >= 0:
            x = self.table[x]
        return x

    def union(self,x,y):
        s1 = self.find(x)
        s2 = self.find(y)
        if s1 != s2:
            if self.table[s1] != self.table[s2]:
                if self.table[s1] < self.table[s2]:
                    self.table[s2] = s1
                else:
                    self.table[s1] = s2
            else:
                self.table[s1] += -1
                self.table[s2] = s1
        return

n,m = map(int,raw_input().split())

uf = UnionFind(n+m)

for i in xrange(n):
	langs = map(int,raw_input().split())
	for j in xrange(1,langs[0] + 1):

		uf.union(i,langs[j]+n-1)

a = uf.find(0)

for i in range(1,n):
	root = uf.find(i)

	if uf.find(i) != a:
		print 'NO'
		quit()

print 'YES'

Solution (Python):
from collections import deque

N, M = map(int, input().split())
G = [[] for i in range(N+M)]
check = [0 for j in range(N+M)]


def bfs(s):
    q = deque()
    check[s] = 1
    q.append(s)

    while len(q) != 0:
        u = q.popleft()
        for v in G[u]:
            if check[v] == 0:
                check[v] = 1
                q.append(v)

        check[u] = 2


def main():
    for i in range(N):
        kl = list(map(int, input().split()))
        for j in range(kl[0]):
            G[i].append(N+kl[j+1]-1)
            G[N+kl[j+1]-1].append(i)

    bfs(0)

    for i in range(N):
        if check[i] == 0:
            print("NO")
            break
    else:
        print("YES")


if __name__ == '__main__':
    main()

Solution (Python):
import sys
sys.setrecursionlimit(10**7)

N, M = map(int, input().split())
P = [[] for i in range(N)]
L = [[] for i in range(M)]
for i in range(N):
    I = list(map(int, input().split()))
    for l in I[1:]:
        P[i].append(l-1)
        L[l-1].append(i)

P_visited = [0] * N
L_visited = [0] * M



def dfs(n, flg):
    if flg:
        P_visited[n] = 1
        for l in P[n]:
            if not L_visited[l]:
                dfs(l, flg ^ 1)
    else:
        L_visited[n] = 1
        for p in L[n]:
            if not P_visited[p]:
                dfs(p, flg ^ 1)


dfs(0, 1)
print("YES" if all(P_visited) else "NO")

Solution (Python):
import sys
sys.setrecursionlimit(2 * 10**5)
N,M = map(int,input().split())

par = [i for i in range(N+M)]
def root(a):
    if par[a] == a: return a
    par[a] = root(par[a])
    return par[a]

def same(a,b):
    return root(a) == root(b)

def unite(a,b):
   ra,rb = root(a),root(b)
   if ra == rb: return
   par[ra] = rb

for i in range(N):
    src = list(map(lambda x:int(x)-1,input().split()))
    if len(src) == 1: continue
    for j in src[1:]:
        unite(i,N+j)

for i in range(1,N):
    if not same(0,i):
        print('NO')
        exit()
print('YES')

Solution (Python):

class unionfind:
    def __init__(self, n):
        self.parent = [-1] * n
    def find(self, x):
        if self.parent[x] < 0:
            return x
        else:
            self.parent[x] = self.find(self.parent[x])
            return self.parent[x]
    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x != y:
            if self.parent[x] > self.parent[y]: x, y = y, x
            self.parent[x] += self.parent[y]
            self.parent[y] = x
    def issame(self, x, y):
        return self.find(x) == self.find(y)

N, M = map(int, input().split())
uf = unionfind(N + M)
for i in range(N):
    L = [int(x) - 1 for x in input().split()]
    for j in range(L[0] + 1):
        uf.unite(L[j + 1], M + i)
print(('NO', 'YES')[all(uf.issame(M, M + i) for i in range(N))])

Solution (Python):

class UnionFind():
    def __init__(self, size):
        self.table = [-1] * size

    def find(self, x):
        if self.table[x] < 0:
            return x
        else:
            self.table[x] = self.find(self.table[x])
            return self.table[x]

    def union(self, x, y):
        s1 = self.find(x)
        s2 = self.find(y)
        if s1 != s2:
            if self.table[s2] < self.table[s1]: s1, s2 = s2, s1
            self.table[s1] += self.table[s2]
            self.table[s2] = s1
        return s1 != s2


N, M = map(int, input().split())
uf = UnionFind(N + M)
for i in range(N):
    L = [int(x) - 1 for x in input().split()]
    L[0] += 1
    for j in range(L[0]):
        uf.union(L[j + 1], M + i)

ans = True
for i in range(N):
    if uf.find(M + i) != uf.find(M):
        ans = False
print(('NO', 'YES')[ans])

Solution (Python):
from sys import stdin, stdout
def readLine_int_list():return list(map(int, stdin.readline().split()))

def find(x):
    if par[x] == x:
        return x
    else:
        par[x] = find(par[x])
        return par[x]
        
def unite(x,y):
    x = find(x)
    y = find(y)
    
    if x==y: return
    if rank[x]<rank[y]:
        par[x] = y
    else:
        par[y] = x
        if rank[x] == rank[y]:
            rank[x]+=1
            
def same(x,y):
    return find(x)==find(y)
    
n,m = readLine_int_list()
v = n + m
par = [i for i in range(0, v)]
rank = [1] * v
def main():
    for i in range(n):
        for ii in readLine_int_list()[1:]:
           unite(i, ii-1+n)
           
    r = "YES"
    for i in range(0, n):
        if find(i) != find(0):
            r = "NO"
    print(r)
    
if __name__ == '__main__':
    main()

Solution (Python):
q,w,e=input,range,int
n,m=map(e,q().split())
V=n+m
p,s=[i for i in w(V)],[1]*V
def f(x):
    if x==p[x]:
        return x
    p[x]=f(p[x]);return p[x]


def u(x, y):
    x, y = f(x), f(y)
    if x==y:
        return
    if s[x] < s[y]:
        x, y = y, x
    p[y] = x
    s[x] += s[y]


[u(i,l-1+n)for i in w(n)for l in [e(k)for k in q().split()][1:]]
print("NO"if len([i for i in w(n)if f(i)!=f(0)])>0 else"YES")

Solution (Python):
q,w,e=input,range,int
n,m=map(e,q().split())
V=n+m
par,sizes=[i for i in w(V)],[1]*V


def f(x):
    if x == par[x]:
        return x
    par[x] = f(par[x])
    return par[x]


def u(x, y):
    x, y = f(x), f(y)
    if x == y:
        return
    if sizes[x] < sizes[y]:
        x, y = y, x
    par[y] = x
    sizes[x] += sizes[y]


[u(i,l-1+n)for i in w(n)for l in [e(k)for k in q().split()][1:]]
print("NO"if len([i for i in w(n)if f(i)!=f(0)])>0 else"YES")

Solution (Python):
q,w,e=input,range,int

n, m = map(e,q().split())
V = n + m
par = [i for i in w(V)]
sizes = [1] * V


def f(x):
    if x == par[x]:
        return x
    par[x] = f(par[x])
    return par[x]


def u(x, y):
    x, y = f(x), f(y)
    if x == y:
        return
    if sizes[x] < sizes[y]:
        x, y = y, x
    par[y] = x
    sizes[x] += sizes[y]


[u(i,l-1+n)for i in w(n)for l in [e(k)for k in q().split()][1:]]
print("NO"if len([i for i in w(n)if f(i)!=f(0)])>0 else"YES")

Solution (Python):
q=input
w=range
n, m = map(int, q().split())
V = n + m
par = [i for i in w(V)]
sizes = [1] * V


def f(x):
    if x == par[x]:
        return x
    par[x] = f(par[x])
    return par[x]


def u(x, y):
    x, y = f(x), f(y)
    if x == y:
        return
    if sizes[x] < sizes[y]:
        x, y = y, x
    par[y] = x
    sizes[x] += sizes[y]


[u(i,l-1+n)for i in w(n)for l in [int(k)for k in q().split()][1:]]
print("NO"if len([i for i in w(n)if f(i)!=f(0)])>0 else"YES")

Solution (Python):
n, m = map(int, input().split())
V = n + m
par = [i for i in range(V)]
sizes = [1] * V


def f(x):
    if x == par[x]:
        return x
    par[x] = f(par[x])
    return par[x]


def unite(x, y):
    x, y = f(x), f(y)
    if x == y:
        return
    if sizes[x] < sizes[y]:
        x, y = y, x
    par[y] = x
    sizes[x] += sizes[y]


[unite(i,l-1+n)for i in range(n)for l in [int(k)for k in input().split()][1:]]
print("NO"if len([i for i in range(n)if f(i)!=f(0)])>0 else"YES")

Solution (Python):
n, m = map(int, input().split())
V = n + m
par = [i for i in range(V)]
sizes = [1] * V


def f(x):
    if x == par[x]:
        return x
    par[x] = f(par[x])
    return par[x]


def unite(x, y):
    x, y = f(x), f(y)
    if x == y:
        return
    if sizes[x] < sizes[y]:
        x, y = y, x
    par[y] = x
    sizes[x] += sizes[y]


for i in range(n):
    for l in [int(k)for k in input().split()][1:]:
        unite(i,l-1+n)
print("NO"if len([i for i in range(n)if f(i)!=f(0)])>0 else"YES")

Solution (Python):
n, m = map(int, input().split())
V = n + m
par = [i for i in range(0, V)]
sizes = [1] * V


def find(x):
    if x == par[x]:
        return x
    par[x] = find(par[x])
    return par[x]


def unite(x, y):
    x = find(x)
    y = find(y)
    if x == y:
        return
    if sizes[x] < sizes[y]:
        x, y = y, x
    par[y] = x
    sizes[x] += sizes[y]


for i in range(0, n):
    for l in [int(k)for k in input().split()][1:]:
        unite(i, l - 1 + n)
print("NO" if len([i for i in range(0, n)if find(i) != find(0)]) > 0 else "YES")

Solution (Python):
n, m = map(int, input().split())
V = n + m
par = [i for i in range(0, V)]
sizes = [1] * V


def find(x):
    if x == par[x]:
        return x
    par[x] = find(par[x])
    return par[x]


def unite(x, y):
    x = find(x)
    y = find(y)
    if x == y:
        return
    if sizes[x] < sizes[y]:
        x, y = y, x
    par[y] = x
    sizes[x] += sizes[y]


for i in range(0, n):
    for l in [int(k)for k in input().split()][1:]:
        unite(i, l - 1 + n)
r = "YES"
if len([i for i in range(0, n)if find(i) != find(0)]) > 0:
    r = "NO"
print(r)

Solution (Python):
n, m = map(int, input().split())
V = n + m
par = [i for i in range(0, V)]
sizes = [1] * V


def find(x):
    if x == par[x]:
        return x
    par[x] = find(par[x])
    return par[x]


def unite(x, y):
    x = find(x)
    y = find(y)
    if x == y:
        return
    if sizes[x] < sizes[y]:
        x, y = y, x
    par[y] = x
    sizes[x] += sizes[y]


for i in range(0, n):
    for l in [int(k)for k in input().split()][1:]:
        unite(i, l - 1 + n)
r = "YES"
for i in range(0, n):
    if find(i) != find(0):
        r = "NO"
print(r)

Solution (Python):
import math,string,itertools,fractions,heapq,collections,re,array,bisect,sys,random,time

sys.setrecursionlimit(10**7)
inf = 10**10
mod = 10**9 + 7

class UnionFind:
    def __init__(self, size):
        self.table = [-1 for _ in range(size)]

    def find(self, x):
        if self.table[x] < 0:
            return x
        else:
            self.table[x] = self.find(self.table[x])
            return self.table[x]

    def union(self, x, y):
        s1 = self.find(x)
        s2 = self.find(y)
        if s1 != s2:
            if self.table[s1] <= self.table[s2]:
                self.table[s1] += self.table[s2]
                self.table[s2] = s1
            else:
                self.table[s2] += self.table[s1]
                self.table[s1] = s2
            return True
        return False

    def subsetall(self):
        a = []
        for i in range(len(self.table)):
            if self.table[i] < 0:
                a.append((i, -self.table[i]))
        return a

def f():
    n,m = list(map(int, input().split()))
    a = list(range(m+1))
    g = [False]*(m+1)
    uf = UnionFind(m+1)
    mi = None
    for _ in range(n):
        c = list(map(int, input().split()))
        if not mi:
            mi = c[1]
        g[c[1]] = True
        if c[0] > 1:
            for i in range(c[0]-1):
                g[c[2+i]] = True
                uf.union(c[1], c[2+i])

    t = uf.find(mi)

    for i in range(m+1):
        if not g[i]:
            continue
        if uf.find(i) != t:
            return 'NO'
    return 'YES'



print(f())

Solution (Python):
import sys

next(sys.stdin)

_, *langs = map(int, next(sys.stdin).strip().split())
common_langs = set(langs)

unreachable = list()
for line in sys.stdin:
    _, *langs = map(int, line.strip().split())
    unreachable.append(set(langs))

change = True
while change:
    change = False
    for langs in unreachable:
        if len(common_langs & langs) > 0:
            s = len(common_langs)
            common_langs.update(langs)
            change |= not s == len(common_langs)
            langs.clear()
    unreachable = list(langs for langs in unreachable if len(langs) > 0)

if len(unreachable) == 0:
    print('YES')
else:
    print('NO')

Solution (Python):
from collections import deque
N, M = map(int, raw_input().split())
G = dict()
for n in range(N):
    L = map(int, raw_input().split())
    
    G['A'+str(n+1)] = {'con':False, 'edge':map(str, L[1:])}
    for l in L[1:]:
        if G.has_key(str(l)) == False:
            G[str(l)] = {'con':False, 'edge':['A'+str(n+1)]}
        else:
            G[str(l)]['edge'].append('A'+str(n+1))


queue = deque(['A1'])
G['A1']['con'] = True

while len(queue) > 0:
    q = queue.popleft()
    for p in G[q]['edge']:
        if G[p]['con']:
            pass
        else:
            G[p]['con'] = True
            queue.append(p)
res = 'YES'
for n in range(N):
    if G['A'+str(n+1)]['con'] == False:
        res = 'NO'
        break
print res

Solution (Python):

import sys,copy,math,heapq,itertools as it,fractions,re,bisect,collections as coll

class UnionFind:
    def __init__(self, size):
        self.rank = [0] * size
        self.par = range(size)
        self.g_num = size

    def find(self, x):
        if x == self.par[x]: return x
        self.par[x] = self.find(self.par[x])
        return self.par[x]

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def unite(self, x, y):
        x, y = self.find(x), self.find(y)
        if x == y: return

        self.g_num -= 1
        if (self.rank[x] > self.rank[y]):
            self.par[y] = x
        else:
            self.par[x] = y
            if (self.rank[x] == self.rank[y]): self.rank[y] += 1

    def group_num(self):
        return self.g_num

N, M = map(int, raw_input().split())
L = [map(int, raw_input().split()) for i in xrange(N)]

sp = [-1]*M
uf = UnionFind(N)
for i in xrange(N):
    k = L[i][0]
    for j in xrange(1, k + 1):
        if sp[L[i][j] - 1] == -1:
            sp[L[i][j] - 1] = i
        else:
            uf.unite(sp[L[i][j] - 1], i)

print "YES" if uf.group_num() == 1 else "NO"

Solution (Python):
class UnionFind:
    def __init__(self,size):
        self.parent=range(size)
        self.tree_num=size
        self.tree_w=[1]*size
        self.rank=[0]*size

    def findset(self,x):
        if self.parent[x]==x:
            return x
        else:
            self.parent[x]=self.findset(self.parent[x])
            return self.parent[x]

    def unite(self,x,y):
        x=self.findset(x)
        y=self.findset(y)
        if x==y:
            return
        if self.rank[x]<self.rank[y]:
            self.parent[x]=y
            self.tree_num-=1
            self.tree_w[y]+=self.tree_w[x]
        else:
            self.parent[y]=x
            self.tree_num-=1
            self.tree_w[x]+=self.tree_w[y]
            if self.rank[x]==self.rank[y]:
                self.rank[x]+=1

    def same(self,x,y):
        if self.findset(x)==self.findset(y):
            return True
        else:
            return False

    def tree_number(self):
        return self.tree_num

    def tree_weight(self,x):
        return self.tree_w[self.findset(x)]

n,m=map(int,raw_input().split())
p=[map(int,raw_input().split()) for _ in xrange(n)]
g=[[] for _ in xrange(m)]
for i in xrange(n):
    for j in p[i][1:]:
        g[j-1].append(i)
uf=UnionFind(n)
for i in xrange(m):
    for j in xrange(len(g[i])):
        uf.unite(g[i][0],g[i][j])
if uf.tree_number()==1:
    print("YES")
else:
    print("NO")