#include <bits/stdc++.h>
using namespace std;
const int maxn = 10010, inf = 1e9;
int n, m, S, T, cnt, root1, root2, lc[maxn << 3], rc[maxn << 3], a[maxn], ans;
int head[1000010], to[5000010], nextt[5000010], w[5000010], tot = 1, d[1000010];
struct node {
  int pos, L, R, opt;
} e[maxn * 2];
void add(int x, int y, int z) {
  w[++tot] = z;
  to[tot] = y;
  nextt[tot] = head[x];
  head[x] = tot;
  w[++tot] = 0;
  to[tot] = x;
  nextt[tot] = head[y];
  head[y] = tot;
}
bool bfs() {
  for (int i = 0; i <= T; i++) d[i] = -1;
  d[S] = 0;
  queue<int> q;
  q.push(S);
  while (!q.empty()) {
    int u = q.front();
    q.pop();
    if (u == T) return true;
    for (int i = head[u]; i; i = nextt[i]) {
      int v = to[i];
      if (d[v] == -1 && w[i]) {
        d[v] = d[u] + 1;
        q.push(v);
      }
    }
  }
  return false;
}
int dfs(int u, int f) {
  if (u == T) return f;
  int res = 0;
  for (int i = head[u]; i; i = nextt[i]) {
    int v = to[i];
    if (d[v] == d[u] + 1 && w[i]) {
      int temp = dfs(v, min(f - res, w[i]));
      w[i] -= temp;
      w[i ^ 1] += temp;
      res += temp;
      if (res == f) return res;
    }
  }
  if (!res) d[u] = -1;
  return res;
}
void dinic() {
  while (bfs()) ans += dfs(S, inf);
}
bool cmp(node a, node b) {
  if (a.pos == b.pos) return a.opt > b.opt;
  return a.pos < b.pos;
}
void build1(int &o, int l, int r, int faa, int opt) {
  o = ++cnt;
  if (faa) {
    if (!opt)
      add(o, faa, inf);
    else
      add(faa, o, inf);
  }
  if (l == r) return;
  int mid = (l + r) >> 1;
  build1(lc[o], l, mid, o, opt);
  build1(rc[o], mid + 1, r, o, opt);
}
void build2(int o, int l, int r, int opt) {
  if (l == r) {
    if (!opt)
      add(S, o, 1);
    else
      add(o, T, 1);
    return;
  }
  int mid = (l + r) >> 1;
  build2(lc[o], l, mid, opt);
  build2(rc[o], mid + 1, r, opt);
}
void Modify(int x, int L, int R) {
  for (int i = L; i <= R; i++) a[i] = x;
}
void Add(int o, int l, int r, int x, int y, int from, int opt) {
  if (!o || x > y || y < l || x > r) return;
  if (x <= l && r <= y) {
    if (!opt)
      add(o, from, inf);
    else
      add(from, o, inf);
    return;
  }
  int mid = (l + r) >> 1;
  if (x <= mid) Add(lc[o], l, mid, x, y, from, opt);
  if (y > mid) Add(rc[o], mid + 1, r, x, y, from, opt);
}
void Insert(int x, int L, int R) {
  int last = -1, pos = -1;
  for (int i = L; i <= R + 1; i++) {
    int temp = 0;
    if (i <= R) {
      temp = a[i] + 1;
      a[i] = -1;
    }
    if (i == R + 1 || temp != last) {
      if (pos != -1) {
        int z = ++cnt;
        Add(root1, 1, n, pos, i - 1, z, 0);
        Add(root2, 1, n, last, x, z, 1);
      }
      pos = i;
      last = temp;
    }
  }
}
int main() {
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= m; i++) {
    int x3, y3, x4, y4;
    scanf("%d%d%d%d", &x3, &y3, &x4, &y4);
    e[i * 2 - 1].pos = x3 - 1;
    e[i * 2 - 1].L = y3;
    e[i * 2 - 1].R = y4;
    e[i * 2 - 1].opt = 0;
    e[i * 2].pos = x4;
    e[i * 2].L = y3;
    e[i * 2].R = y4;
    e[i * 2].opt = 1;
  }
  sort(e + 1, e + 1 + 2 * m, cmp);
  build1(root1, 1, n, 0, 0), build1(root2, 1, n, 0, 1);
  for (int i = 1; i <= 2 * m; i++) {
    if (e[i].opt == 0)
      Insert(e[i].pos, e[i].L, e[i].R);
    else
      Modify(e[i].pos, e[i].L, e[i].R);
  }
  Insert(n, 1, n);
  T = ++cnt;
  build2(root1, 1, n, 0), build2(root2, 1, n, 1);
  dinic();
  printf("%d\n", ans);
  return 0;
}
