/*
分析:
2-SAT果题~
第一道2-SAT,很早就知道有这玩意儿了,不过以为很难,就一直没
敢看,不过今儿硬着头皮看完了,不就是缩点+拓扑排序么。。。-、-
数组开小了,1W-、-。另外,这个题还简单点儿,只用回答yes or
no就行了,所以拓扑排序的那一部分不用写。
看来硬着头皮才是应道理呀,囧~
果题,就不啰嗦了。
2012-11-26 13:30
*/
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
#include"math.h"
#include"stack"
#define N 2011
#define M 1000011*2
using namespace std;
int n,m;
int s_index;
int DFN[N],LOW[N];
int belong[N],instack[N];
int cnt;
struct Eage
{
int from,to,next;
}eage1[M],eage2[M];
int tot1,tot2,head1[N],head2[N];
void add1(int a,int b){
eage1[tot1].from=a;eage1[tot1].to=b;eage1[tot1].next=head1[a];head1[a]=tot1++;
}
void add2(int a,int b){
eage2[tot2].from=a;eage2[tot2].to=b;eage2[tot2].next=head2[a];head2[a]=tot2++;
}
void get_map()
{
int a,b,c,d;
int x,y,q,z;
tot1=0;
memset(head1,-1,sizeof(head1));
while(m--)
{
scanf("%d%d%d%d",&a,&b,&c,&d);
x=a*2+c;
if(c) q=x-1;
else q=x+1;
y=b*2+d;
if(d) z=y-1;
else z=y+1;
add1(x,z);add1(y,q);
}
}
stack<int>st;
void Tarjan(int k)
{
int j,v;
st.push(k);
instack[k]=1;
DFN[k]=LOW[k]=++s_index;
for(j=head1[k];j!=-1;j=eage1[j].next)
{
v=eage1[j].to;
if(instack[v]) LOW[k]=LOW[k]>DFN[v]?DFN[v]:LOW[k];
else if(DFN[v]==-1)
{
Tarjan(v);
LOW[k]=LOW[k]>LOW[v]?LOW[v]:LOW[k];
}
}
if(LOW[k]==DFN[k])
{
do
{
j=st.top();
st.pop();
instack[j]=0;
belong[j]=cnt;
}while(j!=k);
cnt++;
}
}
int Judge()
{
int i;
int a,b;
for(i=0;i<n;i++)
{
a=2*i;
b=a+1;
if(belong[a]==belong[b]) return 1;
}
return 0;
}
int main()
{
int i;
int t;
while(scanf("%d%d",&n,&m)!=-1)
{
get_map();
cnt=0;
s_index=0;
memset(LOW,-1,sizeof(LOW));
memset(DFN,-1,sizeof(DFN));
memset(belong,-1,sizeof(belong));
memset(instack,0,sizeof(instack));
for(i=0,t=2*n;i<t;i++) if(DFN[i]==-1) Tarjan(i);
if(Judge()) printf("NO\n");
else printf("YES\n");
}
return 0;
}