class UnionFind:

    def __init__(self, n):

        self.n = n

        self.parents = [-1] * n



    def find(self, x):

        if self.parents[x] < 0:

            return x

        else:

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

            return self.parents[x]



    def union(self, x, y):

        x = self.find(x)

        y = self.find(y)



        if x == y:

            return



        if self.parents[x] > self.parents[y]:

            x, y = y, x



        self.parents[x] += self.parents[y]

        self.parents[y] = x



    def size(self, x):

        return -self.parents[self.find(x)]



    def same(self, x, y):

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



    def members(self, x):

        root = self.find(x)

        return [i for i in range(self.n) if self.find(i) == root]



    def roots(self):

        return [i for i, x in enumerate(self.parents) if x < 0]



    def group_count(self):

        return len(self.roots())



    def all_group_members(self):

        return {r: self.members(r) for r in self.roots()}



    def __str__(self):

        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())



    """

    n個の要素を0 ~ n - 1の番号で管理する。以下の属性およびメソッドを持つ。



    parents

    各要素の親要素の番号を格納するリスト

    要素が根（ルート）の場合は-(そのグループの要素数)を格納する



    find(x)

    要素xが属するグループの根を返す



    union(x, y)

    要素xが属するグループと要素yが属するグループとを併合する



    size(x)

    要素xが属するグループのサイズ（要素数）を返す



    same(x, y)

    要素x, yが同じグループに属するかどうかを返す



    members(x)

    要素xが属するグループに属する要素をリストで返す



    roots()

    すべての根の要素をリストで返す



    group_count()

    グループの数を返す



    all_group_members

    {ルート要素: [そのグループに含まれる要素のリスト], ...}の辞書を返す



    __str__()

    print()での表示用

    ルート要素: [そのグループに含まれる要素のリスト]を文字列で返す

    """





n, m = (int(x) for x in input().split())

L = [set() for _ in range(n)]

for i in range(n):

    k, *arg = (int(x) for x in input().split())

    L[i].update(set(arg))



ANS = L[0]

uf = UnionFind(n)

for _ in range(100):

    for i in range(1, n):

        if ANS & L[i]:

            ANS |= L[i]

            uf.union(0, i)

    for i in reversed(list(range(1, n))):

        if ANS & L[i]:

            ANS |= L[i]

            uf.union(0, i)



if uf.group_count() == 1:

    print("YES")

else:

    print("NO")
class UnionFind:  # 0-index

    def __init__(self, n):

        self.n = n

        self.parents = [-1] * n  # 親の番号 要素が根の場合は-(そのグループの要素数)を格納



    def find(self, x):  # 要素xが属するグループの根を返す

        if self.parents[x] < 0:

            return x

        else:

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

            return self.parents[x]



    def union(self, x, y):  # 要素xが属するグループと要素yが属するグループとを併合する

        x = self.find(x)

        y = self.find(y)

        if x == y:

            return

        if self.parents[x] > self.parents[y]:

            x, y = y, x

        self.parents[x] += self.parents[y]

        self.parents[y] = x



    def size(self, x):  # 要素xが属するグループのサイズ（要素数）を返す

        return -self.parents[self.find(x)]



    def same(self, x, y):  # 要素x, yが同じグループに属するかどうかを返す

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



    def members(self, x):  # 要素xが属するグループに属する要素をリストで返す

        root = self.find(x)

        return [i for i in range(self.n) if self.find(i) == root]



    def roots(self):  # すべての根の要素をリストで返す

        return [i for i, x in enumerate(self.parents) if x < 0]



    def group_count(self):  # グループの数を返す

        return len(self.roots())



    def all_group_members(self):  # {根: [グループに含まれる要素のリスト], ...}の辞書を返す

        return {root: self.members(root) for root in self.roots()}



# ---------------------- #



n, m = (int(x) for x in input().split())

L = [tuple(int(x) for x in input().split()) for _ in range(n)]



uf = UnionFind(n + m)

for i in range(n):

    for l in L[i][1:]:

        l -= 1

        uf.union(i, n + l)



roots = uf.roots()

if len(roots) == 1 or roots[1] >= n:

    print("YES")

else:

    print("NO")

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

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

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        if self.parents[x] > self.parents[y]:
            x, y = y, x
        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def size(self, x):
        return -self.parents[self.find(x)]

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

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        return "\n".join("{}: {}".format(r, self.members(r)) for r in self.roots())

    """
    n個の要素を0 ~ n - 1の番号で管理する。以下の属性およびメソッドを持つ。
    parents
    各要素の親要素の番号を格納するリスト
    要素が根（ルート）の場合は-(そのグループの要素数)を格納する
    find(x)
    要素xが属するグループの根を返す
    union(x, y)
    要素xが属するグループと要素yが属するグループとを併合する
    size(x)
    要素xが属するグループのサイズ（要素数）を返す
    same(x, y)
    要素x, yが同じグループに属するかどうかを返す
    members(x)
    要素xが属するグループに属する要素をリストで返す
    roots()
    すべての根の要素をリストで返す
    group_count()
    グループの数を返す
    all_group_members
    {ルート要素: [そのグループに含まれる要素のリスト], ...}の辞書を返す
    __str__()
    print()での表示用
    ルート要素: [そのグループに含まれる要素のリスト]を文字列で返す
    """


n, m = (int(x) for x in input().split())
L = [set() for _ in range(n)]
for i in range(n):
    k, *arg = (int(x) for x in input().split())
    L[i].update(set(arg))
ANS = L[0]
uf = UnionFind(n)
for _ in range(100):
    for i in range(1, n):
        if ANS & L[i]:
            ANS |= L[i]
            uf.union(0, i)
    for i in reversed(list(range(1, n))):
        if ANS & L[i]:
            ANS |= L[i]
            uf.union(0, i)
if uf.group_count() == 1:
    print("YES")
else:
    print("NO")

class UnionFind:  # 0-index
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n  # 親の番号 要素が根の場合は-(そのグループの要素数)を格納

    def find(self, x):  # 要素xが属するグループの根を返す
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):  # 要素xが属するグループと要素yが属するグループとを併合する
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        if self.parents[x] > self.parents[y]:
            x, y = y, x
        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def size(self, x):  # 要素xが属するグループのサイズ（要素数）を返す
        return -self.parents[self.find(x)]

    def same(self, x, y):  # 要素x, yが同じグループに属するかどうかを返す
        return self.find(x) == self.find(y)

    def members(self, x):  # 要素xが属するグループに属する要素をリストで返す
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):  # すべての根の要素をリストで返す
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):  # グループの数を返す
        return len(self.roots())

    def all_group_members(self):  # {根: [グループに含まれる要素のリスト], ...}の辞書を返す
        return {root: self.members(root) for root in self.roots()}


# ---------------------- #
n, m = (int(x) for x in input().split())
L = [tuple(int(x) for x in input().split()) for _ in range(n)]
uf = UnionFind(n + m)
for i in range(n):
    for l in L[i][1:]:
        l -= 1
        uf.union(i, n + l)
roots = uf.roots()
if len(roots) == 1 or roots[1] >= n:
    print("YES")
else:
    print("NO")

-class UnionFind: +class UnionFind:  # 0-index -        self.parents = [-1] * n +        self.parents = [-1] * n  # 親の番号 要素が根の場合は-(そのグループの要素数)を格納 -    def find(self, x): +    def find(self, x):  # 要素xが属するグループの根を返す -    def union(self, x, y): +    def union(self, x, y):  # 要素xが属するグループと要素yが属するグループとを併合する -    def size(self, x): +    def size(self, x):  # 要素xが属するグループのサイズ（要素数）を返す -    def same(self, x, y): +    def same(self, x, y):  # 要素x, yが同じグループに属するかどうかを返す -    def members(self, x): +    def members(self, x):  # 要素xが属するグループに属する要素をリストで返す -    def roots(self): +    def roots(self):  # すべての根の要素をリストで返す -    def group_count(self): +    def group_count(self):  # グループの数を返す -    def all_group_members(self): -        return {r: self.members(r) for r in self.roots()} - -    def __str__(self): -        return "\n".join("{}: {}".format(r, self.members(r)) for r in self.roots()) - -    """ -    n個の要素を0 ~ n - 1の番号で管理する。以下の属性およびメソッドを持つ。 -    parents -    各要素の親要素の番号を格納するリスト -    要素が根（ルート）の場合は-(そのグループの要素数)を格納する -    find(x) -    要素xが属するグループの根を返す -    union(x, y) -    要素xが属するグループと要素yが属するグループとを併合する -    size(x) -    要素xが属するグループのサイズ（要素数）を返す -    same(x, y) -    要素x, yが同じグループに属するかどうかを返す -    members(x) -    要素xが属するグループに属する要素をリストで返す -    roots() -    すべての根の要素をリストで返す -    group_count() -    グループの数を返す -    all_group_members -    {ルート要素: [そのグループに含まれる要素のリスト], ...}の辞書を返す -    __str__() -    print()での表示用 -    ルート要素: [そのグループに含まれる要素のリスト]を文字列で返す -    """ +    def all_group_members(self):  # {根: [グループに含まれる要素のリスト], ...}の辞書を返す +        return {root: self.members(root) for root in self.roots()} -L = [set() for _ in range(n)] +L = [tuple(int(x) for x in input().split()) for _ in range(n)] +uf = UnionFind(n + m) -    k, *arg = (int(x) for x in input().split()) -    L[i].update(set(arg)) -ANS = L[0] -uf = UnionFind(n) -for _ in range(100): -    for i in range(1, n): -        if ANS & L[i]: -            ANS |= L[i] -            uf.union(0, i) -    for i in reversed(list(range(1, n))): -        if ANS & L[i]: -            ANS |= L[i] -            uf.union(0, i) -if uf.group_count() == 1: +    for l in L[i][1:]: +        l -= 1 +        uf.union(i, n + l) +roots = uf.roots() +if len(roots) == 1 or roots[1] >= n: