#include <bits/stdc++.h>
using namespace std;
inline int getint() {
  int num = 0, flag = 1;
  char c;
  while ((c = getchar()) < '0' || c > '9')
    if (c == '-') flag = -1;
  while (c >= '0' && c <= '9') num = num * 10 + c - 48, c = getchar();
  return num * flag;
}
int n, m, S, T, tot;
int rt1, rt2;
int lc[200005 << 3], rc[200005 << 3];
int tp[200005], fir[200005], nxt[2000005], to[2000005], cap[2000005], cnt = 1;
int h[200005], a[200005];
int ans;
struct node {
  int x, l, r, p;
  friend bool operator<(node x, node y) {
    return x.x == y.x ? x.p > y.p : x.x < y.x;
  }
} q[200005];
inline void newnode(int u, int v, int w) {
  to[++cnt] = v, nxt[cnt] = fir[u], fir[u] = cnt, cap[cnt] = w;
}
inline void insert(int u, int v, int w) { newnode(u, v, w), newnode(v, u, 0); }
inline void build(int &i, int l, int r, int p) {
  if (!i) i = ++tot;
  if (l == r) return;
  int mid = (l + r) >> 1;
  build(lc[i], l, mid, p), build(rc[i], mid + 1, r, p);
  if (p)
    insert(i, lc[i], 0x3f3f3f3f), insert(i, rc[i], 0x3f3f3f3f);
  else
    insert(lc[i], i, 0x3f3f3f3f), insert(rc[i], i, 0x3f3f3f3f);
}
inline void build2(int i, int l, int r, int p) {
  if (l == r) {
    p ? insert(i, T, 1) : insert(S, i, 1);
    return;
  }
  int mid = (l + r) >> 1;
  build2(lc[i], l, mid, p), build2(rc[i], mid + 1, r, p);
}
inline void query(int i, int l, int r, int ql, int qr, int pos, int p) {
  if (qr < l || r < ql) return;
  if (ql <= l && r <= qr) {
    p ? insert(pos, i, 0x3f3f3f3f) : insert(i, pos, 0x3f3f3f3f);
    return;
  }
  int mid = (l + r) >> 1;
  query(lc[i], l, mid, ql, qr, pos, p),
      query(rc[i], mid + 1, r, ql, qr, pos, p);
}
inline void add(int x, int l, int r) {
  int pos = -1, las = -1, y;
  for (int i = l; i <= r; i++) {
    y = a[i] + 1, a[i] = -1;
    if (y != las) {
      if (~pos) {
        int z = ++tot;
        query(rt1, 1, n, pos, i - 1, z, 0), query(rt2, 1, n, las, x, z, 1);
      }
      pos = i, las = y;
    }
  }
  if (~pos) {
    int z = ++tot;
    query(rt1, 1, n, pos, r, z, 0), query(rt2, 1, n, las, x, z, 1);
  }
}
inline void update(int x, int l, int r) {
  for (int i = l; i <= r; i++) a[i] = x;
}
inline bool bfs() {
  queue<int> Q;
  Q.push(S);
  memset(h, -1, sizeof h), h[S] = 0;
  while (!Q.empty()) {
    int u = Q.front();
    Q.pop();
    for (int i = fir[u]; i; i = nxt[i])
      if (cap[i] && !~h[to[i]]) {
        h[to[i]] = h[u] + 1;
        Q.push(to[i]);
        if (to[i] == T) return 1;
      }
  }
  return 0;
}
inline int dfs(int u, int flow) {
  int used = 0;
  if (u == T) return flow;
  for (int &i = tp[u]; i; i = nxt[i])
    if (cap[i] && h[to[i]] == h[u] + 1) {
      int w = dfs(to[i], min(cap[i], flow - used));
      cap[i] -= w, cap[i ^ 1] += w, used += w;
      if (flow == used) return flow;
    }
  if (!used) h[u] = -1;
  return used;
}
inline void dinic() {
  while (bfs()) memcpy(tp, fir, sizeof fir), ans += dfs(S, 0x3f3f3f3f);
}
int main() {
  n = getint(), m = getint();
  cnt = 1;
  build(rt1, 1, n, 0), build(rt2, 1, n, 1);
  for (int i = 1; i <= m; i++) {
    int X1 = getint(), Y1 = getint(), X2 = getint(), Y2 = getint();
    q[2 * i - 1] = (node){X1 - 1, Y1, Y2, 0}, q[2 * i] = (node){X2, Y1, Y2, 1};
  }
  sort(q + 1, q + 2 * m + 1);
  for (int i = 1; i <= 2 * m; i++) {
    if (q[i].p)
      update(q[i].x, q[i].l, q[i].r);
    else
      add(q[i].x, q[i].l, q[i].r);
  }
  add(n, 1, n);
  S = ++tot, T = ++tot;
  build2(rt1, 1, n, 0), build2(rt2, 1, n, 1);
  dinic();
  printf("%d\n", ans);
}
