#include <bits/stdc++.h>
using namespace std;
int n, q, m;
unordered_map<int, int> *resi;
struct FLOW {
  int n, *dist;
  unordered_map<int, int>::const_iterator *rix;
  FLOW(int n) : n(n) {
    dist = (int *)malloc((n + 2) * sizeof(int));
    rix = (unordered_map<int, int>::const_iterator *)malloc(
        (n + 2) * sizeof(unordered_map<int, int>::const_iterator));
    for (int i = 0; i < n + 2; i++)
      for (const auto &ri : resi[i])
        if (ri.second != 0) resi[ri.first][i] = 0;
  }
  ~FLOW() {
    free(dist);
    free(rix);
  }
  int DINIC() {
    int rs = 0;
    for (; DBFS(); rs += DDFS(n, 10000))
      ;
    return rs;
  }
  int DDFS(int x, int flow) {
    if (x == n + 1) return flow;
    int used = 0;
    for (unordered_map<int, int>::const_iterator ri = rix[x];
         ri != resi[x].end(); ri++) {
      int i = (rix[x] = ri)->first, fx;
      if (ri->second != 0 && dist[i] == dist[x] + 1) {
        fx = DDFS(i, min(flow - used, ri->second));
        resi[x][i] -= fx;
        resi[i][x] += fx;
        used += fx;
        if (used == flow) return used;
      }
    }
    if (!used) dist[x] = -1;
    return used;
  }
  bool DBFS() {
    int nn = n + 2;
    for (int i = 0; i < nn; i++) rix[i] = resi[i].begin();
    memset(dist, -1, nn * sizeof(int));
    dist[n] = 0;
    int q[nn], h = 0, r = 1, x;
    q[0] = n;
    while (h < r) {
      if ((x = q[h++]) == n + 1) return true;
      for (const auto &ri : resi[x])
        if (ri.second != 0 && dist[ri.first] == -1)
          dist[ri.first] = dist[x] + 1, q[r++] = ri.first;
    }
    return dist[n + 1] != -1;
  }
};
void update_rect(const set<array<int, 2>> &lazy,
                 const vector<array<int, 2>> &rts, vector<array<int, 2>> &rr,
                 vector<array<int, 2>> &rz) {
  auto ki = lazy.begin();
  auto kj = rts.begin();
  int z1 = (*ki)[0], z2 = (*ki)[1], x1 = (*kj)[0], x2 = (*kj)[1];
  while (ki != lazy.end() || kj != rts.end()) {
    while (ki != lazy.end()) {
      if (z1 == -1) z1 = (*ki)[0], z2 = (*ki)[1];
      auto kix = ++ki;
      ki--;
      if (kix != lazy.end() && (*kix)[0] == z2) {
        z2 = (*kix)[1];
        ki++;
      } else
        break;
    }
    if (ki == lazy.end()) {
      if (x1 != -1) {
        rr.push_back(array<int, 2>{x1, x2});
        kj++;
      }
      rr.reserve(rts.end() - kj);
      rr.insert(rr.end(), kj, rts.end());
      kj = rts.end();
      break;
    } else if (kj == rts.end())
      break;
    if (z1 == -1) z1 = (*ki)[0], z2 = (*ki)[1];
    if (x1 == -1) x1 = (*kj)[0], x2 = (*kj)[1];
    if (z2 <= x1)
      ki++, z1 = -1;
    else if (z2 < x2 && z2 > x1 && z1 <= x1) {
      rz.push_back(array<int, 2>{x1, z2});
      x1 = z2;
      ki++, z1 = -1;
    } else if (z2 < x2 && z2 > x1 && z1 > x1) {
      rr.push_back(array<int, 2>{x1, z1});
      rz.push_back(array<int, 2>{z1, z2});
      x1 = z2;
      ki++, z1 = -1;
    } else if (z1 >= x2) {
      rr.push_back(array<int, 2>{x1, x2});
      kj++, x1 = -1;
    } else if (z2 >= x2 && z1 > x1 && z1 < x2) {
      rr.push_back(array<int, 2>{x1, z1});
      rz.push_back(array<int, 2>{z1, x2});
      kj++, x1 = -1;
    } else if (z2 >= x2 && z1 <= x1) {
      rz.push_back(array<int, 2>{x1, x2});
      kj++, x1 = -1;
    }
  }
}
struct SEG {
  int size, m;
  bool *vis;
  set<array<int, 2>> *lazy, *xlazy;
  SEG(int n) {
    for (this->m = 1; this->m < n; this->m <<= 1)
      ;
    this->size = n;
    vis = new bool[2 * this->m];
    memset(this->vis, false, 2 * this->m * sizeof(bool));
    lazy = new set<array<int, 2>>[2 * this->m];
    xlazy = new set<array<int, 2>>[2 * this->m];
  }
  ~SEG() { delete[] vis, lazy, xlazy; }
  void create_graph(int base, bool dir, int start = -1, int end = -1,
                    int i = 1) {
    if (i == 1) start = 0, end = this->size;
    if (start + 1 == end) {
      if (dir)
        resi[base + i][m * 4 + 1] = 1;
      else
        resi[m * 4][base + i] = 1;
    } else {
      int mid = (start + end) / 2;
      this->create_graph(base, dir, start, mid, i * 2);
      this->create_graph(base, dir, mid, end, i * 2 + 1);
      if (dir) {
        resi[base + i][base + i * 2] = 10000;
        resi[base + i][base + i * 2 + 1] = 10000;
      } else {
        resi[base + i * 2][base + i] = 10000;
        resi[base + i * 2 + 1][base + i] = 10000;
      }
    }
  }
  void create_edge(int node, int l, int r, int start = -1, int end = -1,
                   int i = 1) {
    if (i == 1) start = 0, end = this->size;
    if (r <= start || l >= end)
      ;
    else if (l <= start && r >= end)
      resi[node][m * 2 + i] = 10000;
    else {
      int mid = (start + end) / 2;
      this->create_edge(node, l, r, start, mid, i * 2);
      this->create_edge(node, l, r, mid, end, i * 2 + 1);
    }
  }
  void update(int l, int r, const array<int, 2> &val, int start = -1,
              int end = -1, int i = 1) {
    if (i == 1) start = 0, end = this->size;
    if (r <= start || l >= end)
      ;
    else if (l <= start && r >= end) {
      this->vis[i] = true;
      this->lazy[i].insert(val);
    } else {
      this->vis[i] = true;
      this->xlazy[i].insert(val);
      int mid = (start + end) / 2;
      this->update(l, r, val, start, mid, i * 2);
      this->update(l, r, val, mid, end, i * 2 + 1);
    }
  }
  void query(const vector<array<int, 2>> &rts, int start = -1, int end = -1,
             int i = 1) {
    if (i == 1) start = 0, end = this->size;
    const vector<array<int, 2>> *prt = &rts;
    vector<array<int, 2>> rr, rz, rs;
    if (this->lazy[i].size() != 0) {
      update_rect(this->lazy[i], *prt, rs, rz);
      prt = &rs;
      rz.clear();
    }
    if (this->xlazy[i].size() != 0) {
      update_rect(this->xlazy[i], *prt, rr, rz);
      prt = &rr;
    }
    if (start + 1 < end && (this->vis[i * 2] || this->vis[i * 2 + 1])) {
      int mid = (start + end) / 2;
      this->query(rz, start, mid, i * 2);
      this->query(rz, mid, end, i * 2 + 1);
    }
    for (auto &rt : *prt)
      if (rt[0] != -1) this->create_edge(i, rt[0], rt[1]);
  }
};
int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cin >> n >> q;
  int x1, x2, y1, y2;
  SEG seg(n);
  m = seg.m;
  resi = new unordered_map<int, int>[m * 4 + 2];
  seg.create_graph(0, false);
  seg.create_graph(m * 2, true);
  for (int i = 0; i < q; i++) {
    cin >> x1 >> y1 >> x2 >> y2;
    array<int, 2> val = {y1 - 1, y2};
    seg.update(x1 - 1, x2, val);
  }
  vector<array<int, 2>> rts = {{0, n}};
  seg.query(rts);
  FLOW flow(m * 4);
  cout << flow.DINIC() << endl;
  delete[] resi;
  return 0;
}
