# cf16-finalC - Interpretation

# bipartite graph

def dfs() -> None:

    stack = [(1, 1)]

    seen_m[1] = 1

    while stack:

        v, flg = stack.pop()

        if flg:

            for u in men[v]:

                if not seen_l[u]:

                    stack.append((u, 0))

                    seen_l[u] = 1

        else:

            for u in langs[v]:

                if not seen_m[u]:

                    stack.append((u, 1))

                    seen_m[u] = 1





def main():

    global men, langs, seen_m, seen_l

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

    A = tuple(tuple(map(int, input().split())) for _ in range(N))

    men, langs = [[] for _ in range(N + 1)], [[] for _ in range(M + 1)]

    for person, lang in enumerate(A, 1):  # construct a bipartite graph

        for l in lang[1:]:

            men[person].append(l), langs[l].append(person)

    seen_m, seen_l = [0] * (N + 1), [0] * (M + 1)

    dfs()

    flg = all(i for i in seen_m[1:])

    print(("YES" if flg else "NO"))





if __name__ == "__main__":

    main()
# cf16-finalC - Interpretation

class UnionFind:  # O(α(N))

    def __init__(self, size):  # construct a Union-Find tree (1-idx)

        self.parent = [i for i in range(size + 1)]

        self.rank = [0] * (size + 1)



    def find(self, x):  # find the group (root) of a vertex

        if self.parent[x] == x:

            return x

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

        return self.parent[x]



    def is_same(self, x, y):  # check two vertices are in the same group

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



    def unite(self, x, y):  # unite two groups

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

        if x == y:  # in the same group

            return

        # unite a small one to a bigger one to balance trees

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

            self.parent[x] = y

        else:

            self.parent[y] = x

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

                self.rank[x] += 1





def main():

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

    A = tuple(tuple(map(int, input().split())) for _ in range(N))

    uf, spoken = UnionFind(M), set()

    for _, *langs in A:

        spoken.update(langs)

        primary = langs[0]

        for l in langs[1:]:

            uf.unite(primary, l)

    cur = uf.find(spoken.pop())

    flg = all(uf.find(lang) == cur for lang in spoken)

    print(("YES" if flg else "NO"))





if __name__ == "__main__":

    main()
# cf16-finalC - Interpretation
# bipartite graph
def dfs() -> None:
    stack = [(1, 1)]
    seen_m[1] = 1
    while stack:
        v, flg = stack.pop()
        if flg:
            for u in men[v]:
                if not seen_l[u]:
                    stack.append((u, 0))
                    seen_l[u] = 1
        else:
            for u in langs[v]:
                if not seen_m[u]:
                    stack.append((u, 1))
                    seen_m[u] = 1


def main():
    global men, langs, seen_m, seen_l
    N, M = tuple(map(int, input().split()))
    A = tuple(tuple(map(int, input().split())) for _ in range(N))
    men, langs = [[] for _ in range(N + 1)], [[] for _ in range(M + 1)]
    for person, lang in enumerate(A, 1):  # construct a bipartite graph
        for l in lang[1:]:
            men[person].append(l), langs[l].append(person)
    seen_m, seen_l = [0] * (N + 1), [0] * (M + 1)
    dfs()
    flg = all(i for i in seen_m[1:])
    print(("YES" if flg else "NO"))


if __name__ == "__main__":
    main()

# cf16-finalC - Interpretation
class UnionFind:  # O(α(N))
    def __init__(self, size):  # construct a Union-Find tree (1-idx)
        self.parent = [i for i in range(size + 1)]
        self.rank = [0] * (size + 1)

    def find(self, x):  # find the group (root) of a vertex
        if self.parent[x] == x:
            return x
        self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def is_same(self, x, y):  # check two vertices are in the same group
        return self.find(x) == self.find(y)

    def unite(self, x, y):  # unite two groups
        x, y = self.find(x), self.find(y)
        if x == y:  # in the same group
            return
        # unite a small one to a bigger one to balance trees
        if self.rank[x] < self.rank[y]:
            self.parent[x] = y
        else:
            self.parent[y] = x
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1


def main():
    N, M = list(map(int, input().split()))
    A = tuple(tuple(map(int, input().split())) for _ in range(N))
    uf, spoken = UnionFind(M), set()
    for _, *langs in A:
        spoken.update(langs)
        primary = langs[0]
        for l in langs[1:]:
            uf.unite(primary, l)
    cur = uf.find(spoken.pop())
    flg = all(uf.find(lang) == cur for lang in spoken)
    print(("YES" if flg else "NO"))


if __name__ == "__main__":
    main()

-# bipartite graph -def dfs() -> None: -    stack = [(1, 1)] -    seen_m[1] = 1 -    while stack: -        v, flg = stack.pop() -        if flg: -            for u in men[v]: -                if not seen_l[u]: -                    stack.append((u, 0)) -                    seen_l[u] = 1 +class UnionFind:  # O(α(N)) +    def __init__(self, size):  # construct a Union-Find tree (1-idx) +        self.parent = [i for i in range(size + 1)] +        self.rank = [0] * (size + 1) + +    def find(self, x):  # find the group (root) of a vertex +        if self.parent[x] == x: +            return x +        self.parent[x] = self.find(self.parent[x]) +        return self.parent[x] + +    def is_same(self, x, y):  # check two vertices are in the same group +        return self.find(x) == self.find(y) + +    def unite(self, x, y):  # unite two groups +        x, y = self.find(x), self.find(y) +        if x == y:  # in the same group +            return +        # unite a small one to a bigger one to balance trees +        if self.rank[x] < self.rank[y]: +            self.parent[x] = y -            for u in langs[v]: -                if not seen_m[u]: -                    stack.append((u, 1)) -                    seen_m[u] = 1 +            self.parent[y] = x +            if self.rank[x] == self.rank[y]: +                self.rank[x] += 1 -    global men, langs, seen_m, seen_l -    N, M = tuple(map(int, input().split())) +    N, M = list(map(int, input().split())) -    men, langs = [[] for _ in range(N + 1)], [[] for _ in range(M + 1)] -    for person, lang in enumerate(A, 1):  # construct a bipartite graph -        for l in lang[1:]: -            men[person].append(l), langs[l].append(person) -    seen_m, seen_l = [0] * (N + 1), [0] * (M + 1) -    dfs() -    flg = all(i for i in seen_m[1:]) +    uf, spoken = UnionFind(M), set() +    for _, *langs in A: +        spoken.update(langs) +        primary = langs[0] +        for l in langs[1:]: +            uf.unite(primary, l) +    cur = uf.find(spoken.pop()) +    flg = all(uf.find(lang) == cur for lang in spoken)