#include <bits/stdc++.h>
using namespace std;

struct MaxFlowDinic {
    typedef int flow_t;
    struct Edge {
        int next;
        size_t inv; /* inverse edge index */
        flow_t res; /* residual */
    };
    int n;
    vector<vector<Edge>> graph;
    vector<int> q, l, start;
    void init(int _n) {
        n = _n;
        graph.resize(n);
        for (int i = 0; i < n; i++) graph[i].clear();
    }
    void add_edge(int s, int e, flow_t cap, flow_t caprev = 0) {
        Edge forward{ e, graph[e].size(), cap };
        Edge reverse{ s, graph[s].size(), caprev };
        graph[s].push_back(forward);
        graph[e].push_back(reverse);
    }
    bool assign_level(int source, int sink) {
        int t = 0;
        memset(&l[0], 0, sizeof(l[0]) * l.size());
        l[source] = 1;
        q[t++] = source;
        for (int h = 0; h < t && !l[sink]; h++) {
            int cur = q[h];
            for (const auto& e : graph[cur]) {
                if (l[e.next] || e.res == 0) continue;
                l[e.next] = l[cur] + 1;
                q[t++] = e.next;
            }
        }
        return l[sink] != 0;
    }
    flow_t block_flow(int cur, int sink, flow_t current) {
        if (cur == sink) return current;
        for (int& i = start[cur]; i < graph[cur].size(); i++) {
            auto& e = graph[cur][i];
            if (e.res == 0 || l[e.next] != l[cur] + 1) continue;
            if (flow_t res = block_flow(e.next, sink, min(e.res, current))) {
                e.res -= res;
                graph[e.next][e.inv].res += res;
                return res;
            }
        }
        return 0;
    }
    flow_t solve(int source, int sink) {
        q.resize(n);
        l.resize(n);
        start.resize(n);
        flow_t ans = 0;
        while (assign_level(source, sink)) {
            memset(&start[0], 0, sizeof(start[0]) * n);
            while (flow_t flow = block_flow(source, sink, numeric_limits <flow_t
                        >::max()))
                ans += flow;
        }
        return ans;
    }
};

struct MaxFlowEdgeDemands
{
    MaxFlowDinic mf;
    using flow_t = MaxFlowDinic::flow_t;
    vector<flow_t> ind, outd;
    flow_t D; int n;
    void init(int _n) {
        n = _n; D = 0; mf.init(n + 2);
        ind.clear(); outd.clear();
        ind.resize(n, 0); outd.resize(n, 0);
    }
    void add_edge(int s, int e, flow_t cap, flow_t demands = 0) {
        mf.add_edge(s, e, cap - demands);
        D += demands; ind[e] += demands; outd[s] += demands;
    }
    // returns { false, 0 } if infeasible
    // { true, maxflow } if feasible
    pair<bool, flow_t> solve(int source, int sink) {
        mf.add_edge(sink, source, numeric_limits <flow_t >::max());
        for (int i = 0; i < n; i++) {
            if (ind[i]) mf.add_edge(n, i, ind[i]);
            if (outd[i]) mf.add_edge(i, n + 1, outd[i]);
        }
        if (mf.solve(n, n + 1) != D) return{ false, 0 };
        for (int i = 0; i < n; i++) {
            if (ind[i]) mf.graph[i].pop_back();
            if (outd[i]) mf.graph[i].pop_back();
        }
        return{ true, mf.solve(source, sink) };
    }
};

int lbottom(int t)
{
    return t;
}

int lup(int t)
{
    return 200 + t;
}

int rbottom(int t)
{
    return 400 + t;
}

int rup(int t)
{
    return 600 + t;
}

int next_blk(int t)
{
    if (t > 400 && t <= 600) return lup(t - 400);
    else return lbottom(t - 600);
}

bool loop[444];
bool edge[444];
int x[444][444];

int main()
{
    int n, h;
    scanf("%d%d",&n,&h);
    MaxFlowEdgeDemands mf;
    mf.init(402);
    for (int i = 0; i < n; i++)
    {
        int a, b, c, d;
        scanf("%d%d%d%d",&a,&b,&c,&d);

        int lidx, ridx;

        if (c == 0) lidx = lbottom(a);
        else lidx = lup(c);

        if (d == 0) ridx = rbottom(b);
        else ridx = rup(d);

        ridx = next_blk(ridx);

        x[lidx][ridx]++;
    }

    queue<int> que;

    for (int i = 1; i <= 400; i++)
    {
        int indeg = 0, outdeg = 0;
        for (int j = 1; j <= 400; j++)
        {
            indeg += x[i][j];
            outdeg += x[j][i];
        }

        if (indeg != outdeg)
        {
            edge[i] = true;
            que.push(i);
        }
    }

    while (que.empty() == false)
    {
        int t = que.front(); que.pop();
        for (int j = 1; j <= 400; j++)
        {
            if ((x[t][j] || x[j][t]) && edge[j] == false)
            {
                edge[j] = true;
                que.push(j);
            }
        }
    }

    for (int i = 1; i <= 400; i++)
    {
        if (edge[i]) continue;
        for (int j = 1; j <= 400; j++)
        {
            if (x[i][j] || x[j][i])
            {
                printf("NO\n");
                return 0;
            }
        }
    }

    for (int i = 1; i <= 400; i++)
    {
        for (int j = i + 1; j <= 400; j++)
        {
            if (x[i][j] > x[j][i]) mf.add_edge(i, j, x[i][j] - x[j][i], x[i][j] - x[j][i]);
            else if (x[i][j] < x[j][i]) mf.add_edge(j, i, -x[i][j] + x[j][i], -x[i][j] + x[j][i]);
        }
    }
    for (int i = 1; i <= 200; i++) mf.add_edge(0, i, 1e9);
    for (int i = 201; i <= 400; i++) mf.add_edge(i, 401, 1e9);
    if (mf.solve(0, 401).first) printf("YES\n");
    else printf("NO\n");
}


Measured memory_bytes: 4480