/*
分析:
2-SAT基础题。
哦也,菜鸟第二道2-SAT~。
对于每个人,要么回家、要么不回家,所以:拆点~,将一个人
活生生、血淋淋的-、-I拆成俩,既出现了a和!a。
然后说说建边的事儿:
队长和队员应该是:!a->b,!a->c !b->a,!c->a
每一个关系对里面:a->!b,b->!a
同时,要把一个队伍里面的两队员建立b->c、c->b以及!b->
!a、!a->!b的边(但是,事实上,这四条边即使不建立了,同样
ac,不着为啥。是数据弱,还是前面的思路已经涵盖这个了,暂
时牟想通0.0,欢迎懂的牛牛留言~)
2012-11-27
*/
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
#include"stack"
#define N 1011
#define M 20011
using namespace std;
int n,m;
int s_index,cnt;
int DFN[6*N],LOW[6*N];
int instack[6*N],belong[6*N];
struct Eage{
int from,to,next;
}eage[M];
int tot,head[6*N];
void add(int a,int b){
eage[tot].from=a;eage[tot].to=b;eage[tot].next=head[a];head[a]=tot++;
}
void get_map()
{
int i;
int a,b,c;
int base=3*n;
tot=0;
memset(head,-1,sizeof(head));
for(i=0;i<n;i++)
{
scanf("%d%d%d",&a,&b,&c);
add(b,c);add(c,b);
add(b+base,c+base);add(c+base,b+base);
add(a+base,b);
add(a+base,c);
add(b+base,a);
add(c+base,a);
}
while(m--)
{
scanf("%d%d",&a,&b);
add(a,b+base);
add(b,a+base);
}
}
stack<int>st;
void DFS(int k)
{
int j,v;
st.push(k);
instack[k]=1;
DFN[k]=LOW[k]=++s_index;
for(j=head[k];j!=-1;j=eage[j].next)
{
v=eage[j].to;
if(instack[v]) LOW[k]=LOW[k]>DFN[v]?DFN[v]:LOW[k];
else if(DFN[v]==-1)
{
DFS(v);
LOW[k]=LOW[k]>LOW[v]?LOW[v]:LOW[k];
}
}
if(DFN[k]==LOW[k])
{
do
{
j=st.top();
st.pop();
instack[j]=0;
belong[j]=cnt;
}while(j!=k);
cnt++;
}
}
void Tarjan()
{
int i,t;
cnt=s_index=0;
memset(DFN,-1,sizeof(DFN));
memset(LOW,-1,sizeof(LOW));
memset(belong,-1,sizeof(belong));
memset(instack,0,sizeof(instack));
for(i=0,t=6*n;i<t;i++) if(DFN[i]==-1) DFS(i);
}
int Judge()
{
int i;
int t=3*n;
for(i=0;i<t;i++) if(belong[i]==belong[i+t]) return 1;
return 0;
}
int main()
{
while(scanf("%d%d",&n,&m)!=-1)
{
get_map();
Tarjan();
if(Judge()) printf("no\n");
else printf("yes\n");
}
return 0;
}