import Control.Monad
import Data.Maybe
import qualified Data.ByteString.Char8 as BS
import Data.List
import qualified Data.Vector.Unboxed as VU
import qualified Data.Vector.Unboxed.Mutable as VUM
import qualified Data.Vector as V
import qualified Data.Vector.Mutable as VM

readInt = fst . fromJust . BS.readInt
readIntList = map readInt . BS.words
getInt = readInt <$> BS.getLine
getIntList = readIntList <$> BS.getLine

newUF n = VUM.replicate n (-1 :: Int)

root uf x = do
    p <- VUM.read uf x
    if p < 0
        then return x
        else do
            r <- root uf p
            VUM.write uf x r
            return r

same uf x y = liftM2 (==) (root uf x) (root uf y)

unite uf x y = do
    px <- root uf x
    py <- root uf y
    when (px /= py) $ do
        sx <- VUM.read uf px
        sy <- VUM.read uf py
        let (par, chld) = if sx < sy then (px, py)　else (py, px)
        VUM.write uf chld par
        VUM.write uf par (sx + sy) 

main = do
    [n,m] <- getIntList
    pers <- V.replicateM n $ do
        (k:ls) <- getIntList
        return ls
    let langs = V.create $ do
            vec <- VM.replicate (m+1) []
            forM_ [0..n-1] $ \p -> do
                forM_ (pers V.! p) $ \l -> do
                    VM.modify vec (p:) l
            return vec
    
    let ufvec = VU.create $ do
            uf <- newUF n
            forM_ [1..m] $ \l -> do
                if length (langs V.! l) >= 2 then do
                    let (a:as) = langs V.! l 
                    mapM_ (unite uf a) as
                else return ()
            return uf
    let ans = length . filter (< 0) $ VU.toList ufvec
    putStrLn $ if ans == 1 then "YES" else "NO"