#include <bits/stdc++.h>
using namespace std;
int N, M, Aux[105], source, sink;
vector<pair<int, int> > G[405];
int Rev[805 * 805], Cap[805 * 805], F[805 * 805];
pair<int, int> L[205], R[205];
int cntL, cntR;
const int INF = 1000000005;
int Ind[405], Level[405];
bool Used[405];
queue<int> Q;
pair<pair<int, int>, pair<int, int> > Rectangle[55];
int X[105], Y[105], cntX, cntY, cntE;
void Read() {
  scanf("%d%d", &N, &M);
  for (int i = 1; i <= M; i++) {
    int x1, y1, x2, y2;
    scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
    Rectangle[i] = make_pair(make_pair(x1, y1), make_pair(x2, y2));
    X[++cntX] = x1;
    X[++cntX] = x2;
    Y[++cntY] = y1;
    Y[++cntY] = y2;
  }
  sort(X + 1, X + cntX + 1);
  sort(Y + 1, Y + cntY + 1);
}
void eraseDuplicates(int X[], int& cntX) {
  int cnt = 0;
  for (int i = 1; i <= cntX; i++) {
    if (i == 1 || X[i] != X[i - 1]) Aux[++cnt] = X[i];
  }
  cntX = cnt;
  for (int i = 1; i <= cntX; i++) X[i] = Aux[i];
}
void addEdge(int x, int y, int cap, int revCap) {
  ++cntE;
  G[x].push_back(make_pair(y, cntE));
  Cap[cntE] = cap;
  Rev[cntE] = cntE + 1;
  ++cntE;
  G[y].push_back(make_pair(x, cntE));
  Cap[cntE] = revCap;
  Rev[cntE] = cntE - 1;
}
void buildRange(int X[], int cntX, pair<int, int> L[], int& cntL) {
  for (int i = 1; i <= cntX; i++) {
    L[++cntL] = make_pair(X[i], X[i]);
    if (i < cntX && X[i] + 1 < X[i + 1]) {
      L[++cntL] = make_pair(X[i] + 1, X[i + 1] - 1);
    }
  }
}
void computeLimits(int x1, int y1, int x2, int y2, int& leftL, int& rightL,
                   int& leftR, int& rightR) {
  for (int j = 1; j <= cntL; j++) {
    if (L[j].first >= x1 && L[j].second <= x2) {
      leftL = j;
      break;
    }
  }
  for (int j = 1; j <= cntL; j++)
    if (L[j].first >= x1 && L[j].second <= x2) {
      rightL = j;
    }
  for (int j = 1; j <= cntR; j++) {
    if (R[j].first >= y1 && R[j].second <= y2) {
      leftR = j;
      break;
    }
  }
  for (int j = 1; j <= cntR; j++)
    if (R[j].first >= y1 && R[j].second <= y2) {
      rightR = j;
    }
}
void buildNetwork() {
  source = 0;
  sink = cntL + cntR + 1;
  for (int i = 1; i <= cntL; i++) {
    addEdge(source, i, L[i].second - L[i].first + 1, 0);
  }
  for (int i = 1; i <= cntR; i++) {
    addEdge(i + cntL, sink, R[i].second - R[i].first + 1, 0);
  }
  for (int i = 1; i <= M; i++) {
    int x1 = Rectangle[i].first.first, y1 = Rectangle[i].first.second;
    int x2 = Rectangle[i].second.first, y2 = Rectangle[i].second.second;
    int leftL, rightL, leftR, rightR;
    computeLimits(x1, y1, x2, y2, leftL, rightL, leftR, rightR);
    for (int j = leftL; j <= rightL; j++)
      for (int k = leftR; k <= rightR; k++)
        addEdge(j, k + cntL,
                min(L[j].second - L[j].first + 1, R[k].second - R[k].first + 1),
                0);
  }
}
bool BFS() {
  for (int i = source; i <= sink; i++) Used[i] = false, Level[i] = -1;
  Level[source] = 0;
  Used[source] = true;
  Q.push(source);
  while (!Q.empty()) {
    int node = Q.front();
    Q.pop();
    if (node == sink) continue;
    for (int j = 0; j < G[node].size(); j++) {
      int neighb = G[node][j].first, edge = G[node][j].second;
      if (!Used[neighb] && Cap[edge] - F[edge] > 0) {
        Used[neighb] = true;
        Q.push(neighb);
        Level[neighb] = Level[node] + 1;
      }
    }
  }
  return Used[sink];
}
int pushFlow(int node, int flow) {
  if (node == sink) return flow;
  for (; Ind[node] < G[node].size(); Ind[node]++) {
    int neighb = G[node][Ind[node]].first, edge = G[node][Ind[node]].second;
    if (Cap[edge] - F[edge] > 0 && Level[neighb] == Level[node] + 1) {
      int f = pushFlow(neighb, min(flow, Cap[edge] - F[edge]));
      if (f > 0) {
        F[edge] += f;
        F[Rev[edge]] -= f;
        return f;
      }
    }
  }
  return 0;
}
void init() {
  for (int i = source; i <= sink; i++) Ind[i] = 0;
}
void Dinic() {
  int maxFlow = 0;
  while (BFS()) {
    init();
    int flow = pushFlow(source, INF);
    while (flow > 0) {
      maxFlow += flow;
      flow = pushFlow(source, INF);
    }
  }
  printf("%d\n", maxFlow);
}
int main() {
  Read();
  eraseDuplicates(X, cntX);
  eraseDuplicates(Y, cntY);
  buildRange(X, cntX, L, cntL);
  buildRange(Y, cntY, R, cntR);
  buildNetwork();
  Dinic();
  return 0;
}
