#include <bits/stdc++.h>
using namespace std;
int S, T, N;
namespace D {
const int maxn = 1300005, maxe = 2500005;
struct Edge {
  int to, flow;
  Edge(int t2 = 0, int t3 = 0) {
    to = t2;
    flow = t3;
  }
} Es[maxe];
int d[maxn], nxt[maxe], nfir[maxn], fir[maxn], tot = 1;
queue<int> que;
void add(int x, int y, int w) {
  Es[++tot] = Edge(y, w);
  nxt[tot] = fir[x];
  fir[x] = tot;
  Es[++tot] = Edge(x, 0);
  nxt[tot] = fir[y];
  fir[y] = tot;
}
bool BFS() {
  memset(d, 63, sizeof(d));
  int INF = d[0];
  while (!que.empty()) que.pop();
  que.push(S);
  d[S] = 0;
  while (!que.empty()) {
    int x = que.front();
    que.pop();
    for (int j = fir[x]; j; j = nxt[j])
      if (d[Es[j].to] == INF && Es[j].flow > 0) {
        d[Es[j].to] = d[x] + 1;
        que.push(Es[j].to);
      }
  }
  return d[T] != INF;
}
int find_DFS(int x, int flw) {
  if (x == T || flw == 0) return flw;
  int res = 0, t;
  for (int &j = nfir[x]; j; j = nxt[j]) {
    if (d[x] + 1 == d[Es[j].to] &&
        (t = find_DFS(Es[j].to, min(flw, Es[j].flow))) > 0) {
      Es[j].flow -= t;
      Es[j ^ 1].flow += t;
      res += t;
      flw -= t;
      if (flw == 0) break;
    }
  }
  return res;
}
int Dinic() {
  int MaxFlow = 0, now;
  while (BFS()) {
    for (int i = 1; i <= N; i++) nfir[i] = fir[i];
    MaxFlow += find_DFS(S, 1e+9);
  }
  return MaxFlow;
}
};  // namespace D
const int maxn = 40005;
int n, m;
int rt[2], N_seg, ch[maxn * 2][2];
int Build(int L, int R, int k) {
  int p = ++N_seg;
  if (L == R) {
    if (!k)
      D::add(L, p, 1e9);
    else
      D::add(p, n + L, 1e9);
    return p;
  }
  int mid = (L + R) >> 1;
  ch[p][0] = Build(L, mid, k);
  if (!k)
    D::add(ch[p][0], p, 1e9);
  else
    D::add(p, ch[p][0], 1e9);
  ch[p][1] = Build(mid + 1, R, k);
  if (!k)
    D::add(ch[p][1], p, 1e9);
  else
    D::add(p, ch[p][1], 1e9);
  return p;
}
void Link(int p, int L, int R, int qL, int qR, int id, int k) {
  if (R < qL || qR < L) return;
  if (qL <= L && R <= qR) {
    if (!k)
      D::add(p, id, 1e9);
    else
      D::add(id, p, 1e9);
    return;
  }
  int mid = (L + R) >> 1;
  Link(ch[p][0], L, mid, qL, qR, id, k);
  Link(ch[p][1], mid + 1, R, qL, qR, id, k);
}
struct data {
  int L, R, k;
  data(int t1 = 0, int t2 = 0, int t3 = 0) {
    L = t1;
    R = t2;
    k = t3;
  }
  bool operator<(const data &B) const { return L < B.L; }
};
set<data> Set;
set<data>::iterator it1, it2;
vector<data> V[maxn];
void Solve(data A, int i) {
  if (A.k > i - 1) return;
  N++;
  Link(rt[0], 1, n, A.L, A.R, N, 0);
  Link(rt[1], 1, n, A.k, i - 1, N, 1);
}
int main() {
  scanf("%d%d", &n, &m);
  N_seg = n * 2;
  rt[0] = Build(1, n, 0);
  rt[1] = Build(1, n, 1);
  N = N_seg;
  S = ++N;
  T = ++N;
  for (int i = 1; i <= n; i++) D::add(S, i, 1), D::add(n + i, T, 1);
  Set.insert(data(1, n, 1));
  Set.insert(data(-1e9, -1e9, 0));
  Set.insert(data(1e9, 1e9, 0));
  for (int i = 1; i <= m; i++) {
    int x, _x, y, _y;
    scanf("%d%d%d%d", &x, &y, &_x, &_y);
    V[x].push_back(data(y, _y, 1));
    V[_x + 1].push_back(data(y, _y, -1));
  }
  for (int i = 1; i <= n; i++) {
    for (int j = 0; j < V[i].size(); j++)
      if (V[i][j].k == -1) {
        int qL = V[i][j].L, qR = V[i][j].R, L = qL, R = qR;
        it2 = Set.upper_bound(V[i][j]);
        it1 = it2;
        it1--;
        if (it1->R + 1 == qL) Solve(*it1, i), L = it1->L, Set.erase(it1);
        if (qR == it2->L - 1) Solve(*it2, i), R = it2->R, Set.erase(it2);
        Set.insert(data(L, R, i));
      }
    for (int j = 0; j < V[i].size(); j++)
      if (V[i][j].k == 1) {
        int qL = V[i][j].L, qR = V[i][j].R;
        it2 = Set.upper_bound(V[i][j]);
        it1 = it2;
        it1--;
        Solve(*it1, i);
        int L = it1->L, R = it1->R;
        Set.erase(it1);
        if (L <= V[i][j].L - 1) Set.insert(data(L, V[i][j].L - 1, i));
        if (V[i][j].R + 1 <= R) Set.insert(data(V[i][j].R + 1, R, i));
      }
  }
  for (it1 = Set.begin(); it1 != Set.end(); it1++)
    if (1 <= it1->L && it1->R <= n) Solve(*it1, n + 1);
  printf("%d\n", D::Dinic());
  return 0;
}
