#include <bits/stdc++.h>
using namespace std;
template <typename T>
struct Dinic {
  static const T eps = 1e-9;
  int n, src, sink;
  struct Edge {
    int from, to;
    T f, cap;
  };
  vector<int> dist, Q, work;
  vector<Edge> edges;
  vector<vector<int>> G;
  Dinic(int _n) : n(_n) {
    G.resize(n);
    dist.resize(n);
    Q.resize(n);
    work.resize(n);
  }
  int addEdge(int s, int t, T forwardCap, T backwardCap = 0) {
    int id = edges.size();
    G[s].push_back(id);
    edges.push_back({s, t, 0, forwardCap});
    G[t].push_back(id + 1);
    edges.push_back({t, s, 0, backwardCap});
    return id;
  }
  bool dinicBfs() {
    fill(dist.begin(), dist.begin() + n, -1);
    dist[src] = 0;
    int qt = 0;
    Q[qt++] = src;
    for (int qh = 0; qh < qt; ++qh) {
      int u = Q[qh];
      for (int eid : G[u]) {
        Edge& e = edges[eid];
        int v = e.to;
        if (dist[v] < 0 && e.cap - e.f > eps) {
          dist[v] = dist[u] + 1;
          Q[qt++] = v;
        }
      }
    }
    return dist[sink] >= 0;
  }
  T dinicDfs(int u, T f) {
    if (u == sink) return f;
    for (int& i = work[u]; i < G[u].size(); ++i) {
      int eid = G[u][i];
      Edge& e = edges[eid];
      if (e.cap <= e.f) continue;
      int v = e.to;
      if (dist[v] == dist[u] + 1) {
        T df = dinicDfs(v, min(f, e.cap - e.f));
        if (df > 0) {
          e.f += df;
          edges[eid ^ 1].f -= df;
          return df;
        }
      }
    }
    return 0;
  }
  T maxFlow() {
    assert(src != -1 && sink != -1);
    T result = 0;
    while (dinicBfs()) {
      fill(work.begin(), work.begin() + n, 0);
      for (;;) {
        T delta = dinicDfs(src, numeric_limits<T>::max());
        if (delta <= eps) break;
        result += delta;
      }
    }
    return result;
  }
  vector<bool> minCut() {
    maxFlow();
    vector<bool> ret(n);
    for (int i = 0; i < n; ++i) ret[i] = dist[i] >= 0;
    return ret;
  }
  int na, nb;
  vector<int> matcha, matchb;
  Dinic(int _na, int _nb) : Dinic(_na + _nb + 2) {
    na = _na;
    nb = _nb;
    src = n - 2;
    sink = n - 1;
    for (int i = 0; i < na; ++i) addEdge(src, i, 1);
    for (int i = 0; i < nb; ++i) addEdge(na + i, sink, 1);
  }
  int addMatchEdge(int s, int t) { return addEdge(s, t + na, 1); }
  int maxMatching() {
    int ret = maxFlow();
    matcha.resize(na);
    matchb.resize(nb);
    for (int i = 0; i < na; ++i) {
      for (int eid : G[i]) {
        auto& e = edges[eid];
        if (e.to != src && e.f == 1) {
          matcha[i] = e.to - na;
          matchb[e.to - na] = i;
        }
      }
    }
    return ret;
  }
};
int main() {
  int n, m;
  scanf("%d%d", &n, &m);
  vector<int> x1(m), x2(m), y1(m), y2(m), xs, ys;
  for (int i = 0; i < m; ++i) {
    scanf("%d%d%d%d", &x1[i], &y1[i], &x2[i], &y2[i]);
    ++x2[i];
    ++y2[i];
    xs.push_back(x1[i]);
    xs.push_back(x2[i]);
    ys.push_back(y1[i]);
    ys.push_back(y2[i]);
  }
  sort(xs.begin(), xs.end());
  xs.resize(unique(xs.begin(), xs.end()) - xs.begin());
  sort(ys.begin(), ys.end());
  ys.resize(unique(ys.begin(), ys.end()) - ys.begin());
  const long long INF = 1e9;
  Dinic<long long> g(xs.size() + ys.size() + 2);
  g.src = g.n - 2;
  g.sink = g.n - 1;
  vector<vector<bool>> has(xs.size(), vector<bool>(ys.size()));
  for (int i = 0; i < m; ++i) {
    for (int j = 0; j + 1 < xs.size(); ++j)
      if (x1[i] <= xs[j] && xs[j + 1] <= x2[i])
        for (int k = 0; k + 1 < ys.size(); ++k)
          if (y1[i] <= ys[k] && ys[k + 1] <= y2[i]) has[j][k] = true;
  }
  for (int j = 0; j + 1 < xs.size(); ++j)
    for (int k = 0; k + 1 < ys.size(); ++k)
      if (has[j][k]) {
        g.addEdge(j, k + xs.size(), INF);
        if (false)
          cerr << "xs[j]"
               << "=" << xs[j] << ","
               << "ys[k]"
               << "=" << ys[k] << endl;
      }
  for (int j = 0; j + 1 < xs.size(); ++j)
    g.addEdge(g.src, j, xs[j + 1] - xs[j]);
  for (int j = 0; j + 1 < ys.size(); ++j)
    g.addEdge(j + xs.size(), g.sink, ys[j + 1] - ys[j]);
  printf("%lld\n", g.maxFlow());
}
