题目大意:小时候,乡愁是一枚小小的邮票,我在这头,母亲在那头。
―― 余光中

集训是辛苦的,道路是坎坷的,休息还是必须的。经过一段时间的训练,lcy决定让大家回家放松一下,但是训练还是得照常进行,lcy想出了如下回家规定,每一个队(三人一队)或者队长留下或者其余两名队员同时留下;每一对队员,如果队员A留下,则队员B必须回家休息下,或者B留下,A回家。由于今年集训队人数突破往年同期最高记录,管理难度相当大,lcy也不知道自己的决定是否可行,所以这个难题就交给你了,呵呵,好处嘛~,免费**漂流一日。

解题思路:首先,为队长和每个队员建立限制条件
假设队长是a,另外两个队员是b和c,
队长回去的时候,两个队员都要在,也就是不能回去,那么就要满足 (a V !b) &&(a V !c)
队员回去时,队长不可以回去,那么就要满足(c V b) && !a,转换一下就变成了(c V !a)&& (b V !a)

然后又给出了如果一个队员要留着,另外一个队员必须要回去的条件,假设队员为a和b,那么就要满足
(a V !b) && (b V !a)
这样就建图完成了

#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
#define N 6010

vector<int> G[N];
int n, m, top;
bool mark[N];
int S[N];

void init() {

    for (int i = 0; i < 6 * n; i++)
        G[i].clear();

    int x, y, z;
    for (int i = 0; i < n; i++) {
        scanf("%d%d%d", &x, &y, &z);
        G[2 * x].push_back(2 * y + 1);
        G[2 * x].push_back(2 * z + 1);
        G[2 * y].push_back(2 * x + 1);
        G[2 * z].push_back(2 * x + 1);
    }

    for (int i = 0; i < m; i++) {
        scanf("%d%d", &x, &y);

        G[2 * y + 1].push_back(2 * x);
        G[2 * x + 1].push_back(2 * y);
    }
}

bool dfs(int u) {
    if (mark[u ^ 1])
        return false;
    if (mark[u])
        return true;

    mark[u] = true;
    S[++top] = u;
    for (int i = 0; i < G[u].size(); i++)
        if (!dfs(G[u][i]))
            return false;
    return true;
}

void solve() {
    memset(mark, 0, sizeof(mark));
    for (int i = 0; i < 6 * n; i += 2) {
        top = 0;
        if (!dfs(i)) {
            while (top)
                mark[S[top--]] = false;
            if (!dfs(i ^ 1)) {
                printf("no\n");
                return ;
            }
        }
    }
    printf("yes\n");
}

int main() {
    while (scanf("%d%d", &n, &m) != EOF) {
        init();
        solve();
    }
    return 0;
}