import java.util.*

fun main(args:Array<String>?): Unit {
    val (m, n) = readLine()!!.trim().split(' ').map(String::toInt)
    val lessCount = IntArray(m){0}
    val greaterNode = Array(m){ Stack<Int>() }
    val lowerLimit = Array(m){IntArray(n){0}}
    val upperLimit = Array(m){IntArray(n){100}}
    repeat(m){special ->
        val k = readLine()!!.trim().toInt()
        repeat(k){
            val (s, cond, t) = readLine()!!.trim().split(' ')
            if (cond == "<="){
                if (upperLimit[special][s.toInt() - 1] > t.toInt()) upperLimit[special][s.toInt() - 1] = t.toInt()
            }else {
                if (lowerLimit[special][s.toInt() - 1] < t.toInt()) lowerLimit[special][s.toInt() - 1] = t.toInt()
            }
        }
    }
    if ((0 until m).any{s -> (0 until n).any{lowerLimit[s][it] > upperLimit[s][it]}}) {
        println("No")
        return
    }
    for (i in 1 until m) for (j in 0 until i){
        for (k in 0 until n){
            if (lowerLimit[i][k] > upperLimit[j][k]) {
                if (greaterNode[j].isEmpty() || greaterNode[j].peek() != i){
                    greaterNode[j].add(i)
                    ++lessCount[i]
                }
            }
            if (lowerLimit[j][k] > upperLimit[i][k]) {
                if (greaterNode[i].isEmpty() || greaterNode[i].peek() != j){
                    greaterNode[i].add(j)
                    ++lessCount[j]
                }
            }
        }
    }
    val queue: Queue<Int> = LinkedList<Int>()
    for (i in 0 until m) if (lessCount[i] == 0) queue.add(i)
    while(queue.isNotEmpty()){
        val top = queue.poll()
        for (i in greaterNode[top]) {
            --lessCount[i]
            if (lessCount[i] == 0) queue.add(i)
        }
    }
    println(if (lessCount.all{it == 0}) "Yes" else "No")
}
