#include <bits/stdc++.h>
using namespace std;
struct node {
  int l, r, h;
  bool flag;
  node() {}
  node(int l1, int r1, int h1, bool flag1) : l(l1), r(r1), h(h1), flag(flag1) {}
  bool operator<(const node &a) const {
    if (h != a.h) return h < a.h;
    return flag < a.flag;
  }
} lin[10010 * 2];
struct Tree {
  int h, tag, sum;
} tree[10010 * 10];
int n, tot, s, t;
void pushdown(int id, int l, int r) {
  if (tree[id].tag != 0) {
    tree[id << 1].tag += tree[id].tag;
    tree[id << 1 | 1].tag += tree[id].tag;
    int mid = (l + r) >> 1;
    tree[id << 1].sum += (mid - l + 1) * tree[id].tag;
    tree[id << 1 | 1].sum += (r - mid) * tree[id].tag;
    tree[id].tag = 0;
  }
}
void pushup(int id) {
  tree[id].sum = tree[id << 1].sum + tree[id << 1 | 1].sum;
}
vector<int> a[10010 * 8], w[10010 * 8], rev[10010 * 8];
void add_edge(int u, int v, int len) {
  a[u].push_back(v);
  a[v].push_back(u);
  w[u].push_back(len);
  w[v].push_back(0);
  rev[u].push_back(a[v].size() - 1);
  rev[v].push_back(a[u].size() - 1);
}
int find_lft(int x, int id = 1, int l = 1, int r = n) {
  if (tree[id].sum == 0) return l - 1;
  if (l == r) return l;
  pushdown(id, l, r);
  int mid = (l + r) >> 1;
  if (x <= mid)
    return find_lft(x, id << 1, l, mid);
  else {
    if (tree[id << 1 | 1].sum == 0) return find_lft(x, id << 1, l, mid);
    int res = find_lft(x, id << 1 | 1, mid + 1, r);
    if (res == mid) return find_lft(x, id << 1, l, mid);
    return res;
  }
}
int find_rit(int x, int id = 1, int l = 1, int r = n) {
  if (tree[id].sum == 0) return r + 1;
  if (l == r) return r;
  pushdown(id, l, r);
  int mid = (l + r) >> 1;
  if (x <= mid) {
    if (tree[id << 1].sum == 0) return find_rit(x, id << 1 | 1, mid + 1, r);
    int res = find_rit(x, id << 1, l, mid);
    if (res == mid + 1) return find_rit(x, id << 1 | 1, mid + 1, r);
    return res;
  } else
    return find_rit(x, id << 1 | 1, mid + 1, r);
}
int pl[10010 * 10], pr[10010 * 10];
void build(int l, int r, int id, bool flag) {
  if (l == r) {
    if (flag == 0)
      add_edge(s, id, 1);
    else
      add_edge(id, t, 1);
    return;
  }
  int mid = (l + r) >> 1;
  pl[id] = ++tot;
  pr[id] = ++tot;
  build(l, mid, pl[id], flag);
  build(mid + 1, r, pr[id], flag);
  if (flag == 0) {
    add_edge(pl[id], id, 0x3FFFFFFF);
    add_edge(pr[id], id, 0x3FFFFFFF);
  } else {
    add_edge(id, pl[id], 0x3FFFFFFF);
    add_edge(id, pr[id], 0x3FFFFFFF);
  }
}
void add_edge_lc(int l1, int r1, int tar, int id, bool flag, int l = 1,
                 int r = n) {
  if (l >= l1 && r <= r1) {
    if (flag == 0)
      add_edge(id, tar, 0x3FFFFFFF);
    else
      add_edge(tar, id, 0x3FFFFFFF);
    return;
  }
  int mid = (l + r) >> 1;
  if (l1 <= mid) add_edge_lc(l1, r1, tar, pl[id], flag, l, mid);
  if (r1 > mid) add_edge_lc(l1, r1, tar, pr[id], flag, mid + 1, r);
}
int rtc, rtr;
void add_blo(int l, int r, int lw, int up) {
  if (lw == up) return;
  tot++;
  add_edge_lc(up + 1, lw, tot, rtc, 0);
  add_edge_lc(l, r, tot, rtr, 1);
}
void putline(int l1, int r1, int h, int id = 1, int l = 1, int r = n) {
  if (l >= l1 && r <= r1) {
    tree[id].h = max(tree[id].h, h);
    return;
  }
  int mid = (l + r) >> 1;
  if (l1 <= mid) putline(l1, r1, h, id << 1, l, mid);
  if (r1 > mid) putline(l1, r1, h, id << 1 | 1, mid + 1, r);
}
int get_h(int pos, int id = 1, int l = 1, int r = n) {
  if (l == r) return tree[id].h;
  int mid = (l + r) >> 1;
  if (pos <= mid)
    return max(tree[id].h, get_h(pos, id << 1, l, mid));
  else
    return max(tree[id].h, get_h(pos, id << 1 | 1, mid + 1, r));
}
void cov(int l1, int r1, int id = 1, int l = 1, int r = n) {
  if (l != r) pushdown(id, l, r);
  if (l >= l1 && r <= r1) {
    tree[id].sum += (r - l + 1);
    tree[id].tag++;
    return;
  }
  int mid = (l + r) >> 1;
  if (l1 <= mid) cov(l1, r1, id << 1, l, mid);
  if (r1 > mid) cov(l1, r1, id << 1 | 1, mid + 1, r);
  pushup(id);
}
void recov(int l1, int r1, int id = 1, int l = 1, int r = n) {
  if (l != r) pushdown(id, l, r);
  if (l >= l1 && r <= r1) {
    tree[id].sum -= (r - l + 1);
    tree[id].tag--;
    return;
  }
  int mid = (l + r) >> 1;
  if (l1 <= mid) recov(l1, r1, id << 1, l, mid);
  if (r1 > mid) recov(l1, r1, id << 1 | 1, mid + 1, r);
  pushup(id);
}
int d[10010 * 8], g[10010 * 8];
int dfs(int x, int flw) {
  if (x == t) return flw;
  int flw1 = flw;
  for (int i = 0; i < int(a[x].size()); i++) {
    int u = a[x][i];
    if (w[x][i] != 0 && d[u] == d[x] - 1) {
      int f = dfs(u, min(flw, w[x][i]));
      w[x][i] -= f;
      w[u][rev[x][i]] += f;
      flw -= f;
      if (flw == 0) return flw1;
    }
  }
  if (flw != flw1) return flw1 - flw;
  if (g[d[x]] == 1) {
    d[s] = tot + 1;
    return 0;
  }
  g[d[x]]--;
  int minh = tot;
  for (int i = 0; i < int(a[x].size()); i++)
    if (w[x][i] != 0) minh = min(minh, d[a[x][i]]);
  d[x] = minh + 1;
  g[d[x]]++;
  return 0;
}
int maxflow() {
  g[0] = tot;
  int ans = 0;
  while (d[s] < tot) ans += dfs(s, 0x3FFFFFFF);
  return ans;
}
int q, xl, yl, xr, yr;
int main() {
  scanf("%d%d", &n, &q);
  for (int i = 1; i <= q; i++) {
    scanf("%d%d%d%d", &yl, &xl, &yr, &xr);
    lin[i] = node(xl, xr, yl - 1, 1);
    lin[i + q] = node(xl, xr, yr, 0);
  }
  q *= 2;
  lin[++q] = node(1, n, n, 1);
  s = 1;
  t = 2;
  tot = 2;
  rtc = ++tot;
  build(1, n, rtc, 0);
  rtr = ++tot;
  build(1, n, rtr, 1);
  sort(lin + 1, lin + 1 + q);
  for (int i = 1; i <= q; i++) {
    if (lin[i].flag == 0) {
      int l = find_lft(lin[i].l - 1) + 1;
      int r = find_rit(lin[i].r + 1) - 1;
      if (l < lin[i].l) add_blo(l, lin[i].l - 1, lin[i].h, get_h(l));
      if (r > lin[i].r) add_blo(lin[i].r + 1, r, lin[i].h, get_h(r));
      recov(lin[i].l, lin[i].r);
      putline(min(l, lin[i].l), max(r, lin[i].r), lin[i].h);
    } else {
      int l = find_lft(lin[i].l) + 1;
      int r = find_rit(lin[i].l) - 1;
      if (l <= r) add_blo(l, r, lin[i].h, get_h(l));
      cov(lin[i].l, lin[i].r);
      putline(min(l, lin[i].l), max(r, lin[i].r), lin[i].h);
    }
  }
  printf("%d", maxflow());
}
