# Union-Findデータ構造

class UnionFind:

    def __init__(self, numV):

        self.pars = list(range(numV))

        self.ranks = [0] * numV

    def find(self, x):

        if self.pars[x] == x: return x

        else:

            self.pars[x] = self.find(self.pars[x])

            return self.pars[x]

    def union(self, x, y):

        x, y = self.find(x), self.find(y)

        if x == y: return

        if self.ranks[x] < self.ranks[y]:

            self.pars[x] = y

        else:

            self.pars[y] = x

            if self.ranks[x] == self.ranks[y]:

                self.ranks[x] += 1

    def same(self, x, y):

        return self.find(x) == self.find(y)



N, M = list(map(int, input().split()))

UF = UnionFind(N+M)

for i in range(N):

    K, *Ls = list(map(int, input().split()))

    for L in Ls:

        UF.union(i, L+N-1)



pars = [UF.find(i) for i in range(N)]

print(('YES' if len(set(pars)) == 1 else 'NO'))

import sys

sys.setrecursionlimit(10**9)



def dfs(vNow):

    useds[vNow] = True

    for v2 in adjL[vNow]:

        if not useds[v2]:

            dfs(v2)



N, M = list(map(int, input().split()))

adjL = [[] for v in range(N+M)]

for i in range(N):

    K, *Ls = list(map(int, input().split()))

    for L in Ls:

        adjL[i].append(L+N-1)

        adjL[L+N-1].append(i)



useds = [False] * (N+M)

dfs(0)



print(('YES' if all(useds[:N]) else 'NO'))

# Union-Findデータ構造
class UnionFind:
    def __init__(self, numV):
        self.pars = list(range(numV))
        self.ranks = [0] * numV

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

    def union(self, x, y):
        x, y = self.find(x), self.find(y)
        if x == y:
            return
        if self.ranks[x] < self.ranks[y]:
            self.pars[x] = y
        else:
            self.pars[y] = x
            if self.ranks[x] == self.ranks[y]:
                self.ranks[x] += 1

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


N, M = list(map(int, input().split()))
UF = UnionFind(N + M)
for i in range(N):
    K, *Ls = list(map(int, input().split()))
    for L in Ls:
        UF.union(i, L + N - 1)
pars = [UF.find(i) for i in range(N)]
print(("YES" if len(set(pars)) == 1 else "NO"))

import sys

sys.setrecursionlimit(10**9)


def dfs(vNow):
    useds[vNow] = True
    for v2 in adjL[vNow]:
        if not useds[v2]:
            dfs(v2)


N, M = list(map(int, input().split()))
adjL = [[] for v in range(N + M)]
for i in range(N):
    K, *Ls = list(map(int, input().split()))
    for L in Ls:
        adjL[i].append(L + N - 1)
        adjL[L + N - 1].append(i)
useds = [False] * (N + M)
dfs(0)
print(("YES" if all(useds[:N]) else "NO"))

-# Union-Findデータ構造 -class UnionFind: -    def __init__(self, numV): -        self.pars = list(range(numV)) -        self.ranks = [0] * numV +import sys -    def find(self, x): -        if self.pars[x] == x: -            return x -        else: -            self.pars[x] = self.find(self.pars[x]) -            return self.pars[x] +sys.setrecursionlimit(10**9) -    def union(self, x, y): -        x, y = self.find(x), self.find(y) -        if x == y: -            return -        if self.ranks[x] < self.ranks[y]: -            self.pars[x] = y -        else: -            self.pars[y] = x -            if self.ranks[x] == self.ranks[y]: -                self.ranks[x] += 1 -    def same(self, x, y): -        return self.find(x) == self.find(y) +def dfs(vNow): +    useds[vNow] = True +    for v2 in adjL[vNow]: +        if not useds[v2]: +            dfs(v2) -UF = UnionFind(N + M) +adjL = [[] for v in range(N + M)] -        UF.union(i, L + N - 1) -pars = [UF.find(i) for i in range(N)] -print(("YES" if len(set(pars)) == 1 else "NO")) +        adjL[i].append(L + N - 1) +        adjL[L + N - 1].append(i) +useds = [False] * (N + M) +dfs(0) +print(("YES" if all(useds[:N]) else "NO"))