#include <bits/stdc++.h>
const int N = 2e4 + 10, M = 3e6 + 10, oo = 1e9;
int n, m, S, T, tot;
namespace IO {
const int Rlen = 1 << 22 | 1;
char buf[Rlen], *p1, *p2;
inline char gc() {
  return (p1 == p2) && (p2 = (p1 = buf) + fread(buf, 1, Rlen, stdin), p1 == p2)
             ? EOF
             : *p1++;
}
template <typename T>
inline T get() {
  char ch;
  T x;
  while (!isdigit(ch = gc()))
    ;
  x = ch ^ 48;
  while (isdigit(ch = gc())) x = ((x + (x << 2)) << 1) + (ch ^ 48);
  return x;
}
inline int gi() { return get<int>(); }
}  // namespace IO
using namespace IO;
namespace NETWORK_FLOW {
int Head[M], Next[M], V[M], W[M], cnt = 1;
int dep[M], cur[M];
inline void bi_add(int u, int v, int w) {
  Next[++cnt] = Head[u], V[cnt] = v, W[cnt] = w, Head[u] = cnt;
  Next[++cnt] = Head[v], V[cnt] = u, W[cnt] = 0, Head[v] = cnt;
}
inline bool bfs() {
  memset(dep, 0, sizeof(dep));
  std::queue<int> Q;
  Q.push(S);
  dep[S] = 1, cur[S] = Head[S];
  while (!Q.empty()) {
    int u = Q.front();
    Q.pop();
    for (int register i = Head[u], v = V[i]; i; v = V[i = Next[i]])
      if (!dep[v] && W[i]) {
        dep[v] = dep[u] + 1, cur[v] = Head[v];
        if (v == T) return 1;
        Q.push(v);
      }
  }
  return 0;
}
inline int dfs(int u, int dist) {
  if (u == T || !dist) return dist;
  for (int &i = cur[u], v = V[i]; i; v = V[i = Next[i]]) {
    if (dep[v] == dep[u] + 1 && W[i]) {
      int d = dfs(v, std::min(dist, W[i]));
      if (d > 0) {
        W[i] -= d, W[i ^ 1] += d;
        return d;
      }
    }
  }
  return 0;
}
inline int dinic(int ret = 0) {
  while (bfs())
    while (int D = dfs(S, oo)) ret += D;
  return ret;
}
}  // namespace NETWORK_FLOW
using NETWORK_FLOW::bi_add;
namespace SGT {
int id[N << 2], tag[N << 2];
inline void pushup(int root) {
  id[root] = ++tot;
  if (!tag[(root << 1)]) bi_add(id[root], id[(root << 1)], oo);
  if (!tag[(root << 1 | 1)]) bi_add(id[root], id[(root << 1 | 1)], oo);
}
inline void build(int root, int l, int r) {
  if (l == r) return void(id[root] = n + l);
  int mid = l + r >> 1;
  build((root << 1), l, mid), build((root << 1 | 1), mid + 1, r);
  pushup(root);
}
inline void update(int root, int l, int r, int ql, int qr, int val) {
  if (ql <= l && r <= qr) return void(tag[root] += val);
  int mid = l + r >> 1;
  if (ql <= mid) update((root << 1), l, mid, ql, qr, val);
  if (qr > mid) update((root << 1 | 1), mid + 1, r, ql, qr, val);
  pushup(root);
}
}  // namespace SGT
using SGT::update;
struct node {
  int l, r, val;
};
std::vector<node> V[N];
int main() {
  n = gi(), m = gi(), tot = 2 * n + 2;
  S = 2 * n + 1;
  T = 2 * n + 2;
  for (int register i = 1; i <= m; ++i) {
    int x1 = gi(), y1 = gi(), x2 = gi(), y2 = gi();
    V[x1].push_back((node){y1, y2, 1});
    V[x2 + 1].push_back((node){y1, y2, -1});
  }
  for (int register i = 1; i <= n; ++i) bi_add(S, i, 1), bi_add(i + n, T, 1);
  SGT::build(1, 1, n);
  for (int register i = 1; i <= n; ++i) {
    for (int register j = 0; j < V[i].size(); ++j)
      update(1, 1, n, V[i][j].l, V[i][j].r, V[i][j].val);
    if (!SGT::tag[1]) bi_add(i, SGT::id[1], oo);
  }
  printf("%d\n", NETWORK_FLOW::dinic());
}
