// Original C++ solution (slower):
#include <cstdio>

#include <cstring>

#include <vector>

using std::vector;



#define MAXN 100005

#define MAXH 405

int indeg[MAXH],outdeg[MAXH];

bool vis[MAXH];

vector<int> G[MAXH];



void add_edge(int u,int v)

{

    outdeg[u]++;indeg[v]++;

    G[u].push_back(v);G[v].push_back(u);

}



bool dfs(int v)

{

    bool f=indeg[v]!=outdeg[v];

    vis[v]=true;

    for(auto to:G[v])

    {

        if(!vis[to]) 

            f|=dfs(to);

    }

    return f;

}



int main()

{

    int N,H;

    int a[MAXN],b[MAXN],c[MAXN],d[MAXN];

    scanf("%d%d",&N,&H);

    for(int i=1;i<=N;i++) 

    {

        scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);

        int l,r;

        l= ( c[i]==0 ? a[i] : -c[i] );

        r= ( d[i]==0 ? -b[i] : d[i] );

        add_edge(l+H,r+H);

    }



    bool flag=true;

    for(int i=0;flag && i<=H;i++) 

    {

        if(outdeg[i]>indeg[i]) 

            flag=false;

    }

    for(int i=H+1;flag && i<=2*H;i++)

    {

        if(indeg[i]>outdeg[i]) 

             flag=false;

    }



    memset(vis,false,sizeof(vis));

    for(int i=0;flag && i<=2*H;i++)

    {

        if((indeg[i]||outdeg[i])&&!vis[i]) 

            flag &=dfs(i);

    }



    if(flag) 

    {

        printf("YES\n"); 

    }

    else

    { 

        printf("NO\n");

    }

    return 0;

}

// Optimized solution to the same problem (faster):
#include<cstdio>

#include<cstring>

#define retrun return

#define cpnst const

int CT[444][444],DEG[444],SZ[444],Lm=401;

class UFS

{

	int Fa[1111];

	public:

	void init(){for(register int i=1;i<=1000;i++)Fa[i]=i;}

	int rt(int x){return Fa[x]^x?Fa[x]=rt(Fa[x]):x;}

	bool merge(int x,int y){return x=rt(x),y=rt(y),Fa[x]=y,x^y;}

}U;

void rd()

{

	int a,b,c,d;

	scanf("%d%d%d%d",&a,&b,&c,&d);

	if(c)a=-c;if(d)b=d;else b=-b;

	U.merge(a+201,b+201),CT[a+201][b+201]++,

	DEG[a+201]++,DEG[b+201]--,SZ[a+201]++,SZ[b+201]++;

}

int UNB[11111];

void cover(int x)

{UNB[U.rt(x)]=1;}

int main()

{

	register int i;

	int n;

	scanf("%d%*d",&n),U.init();

	for(i=1;i<=n;i++)rd();

	for(i=-200;i<=200;i++)

	{

		if(i<0&&DEG[i+201]>0)return puts("NO"),0;

		if(i>0&&DEG[i+201]<0)return puts("NO"),0;

	}for(i=1;i<=Lm;i++)

		if(DEG[i])cover(i);

	for(i=1;i<=Lm;i++)

		if(SZ[i])

			if(!UNB[U.rt(i)])return puts("NO"),0;

	puts("YES");

}

/*

Just go for it.

*/

// Fastest known solution for this problem:
#include "bits/stdc++.h"

using namespace std;



vector<int> g[505];

int l_cnt[505], r_cnt[505];

bool used[505];



int print(bool ok) {

        if (ok) cout << "YES" << endl;

        else cout << "NO" << endl;

        return 0;

}



bool dfs(int v) {

        used[v] = true;

        bool res = l_cnt[v] != r_cnt[v];

        for (auto u : g[v]) if (!used[u]) res |= dfs(u);

        return res;

}



int main() {

        int n, h, a, b, c, d;

        cin >> n >> h;

        for (int i = 0; i < n; i ++) {

                cin >> a >> b >> c >> d;

                int lh = (c == 0 ? a : c + 250);

                int rh = (d == 0 ? b + 250 : d);

                l_cnt[lh] ++;

                r_cnt[rh] ++;

                g[lh].push_back(rh);

                g[rh].push_back(lh);

        }

        for (int i = 0; i < h + 1; i ++) if (r_cnt[i] > l_cnt[i]) return print(0);

        for (int i = 251; i < h + 251; i ++) if (l_cnt[i] > r_cnt[i]) return print(0);

        for (int i = 0; i < 501; i ++) if (!used[i]) if (!g[i].empty()) if (!dfs(i)) return print(0);

        return print(1);

}