#include <bits/stdc++.h>
using namespace std;
struct Network {
  int V = 2;
  const int source = 0, sink = 1;
  struct Edge {
    int source, target, id, reverse;
  };
  vector<vector<Edge>> adjacency_list;
  vector<int> capacities;
  Network() : adjacency_list(2) {}
  int add_vertex() {
    adjacency_list.push_back({});
    return V++;
  }
  void add_edge(const int source, const int target, const int capacity) {
    const auto id = int(capacities.size());
    const auto reverse = id + 1;
    adjacency_list[source].push_back({source, target, id, reverse});
    adjacency_list[target].push_back({target, source, reverse, id});
    capacities.insert(end(capacities), {capacity, 0});
  }
  int maxflow() {
    auto distances = vector<int>(V);
    auto cursors = vector<vector<Edge>::iterator>(V);
    const function<int(int, int)> dfs = [&](const int v, const int flow) {
      if (v == sink) return flow;
      for (auto& e = cursors[v]; e != end(adjacency_list[v]); e++) {
        if (capacities[e->id] &&
            distances[e->target] == distances[e->source] + 1) {
          if (const auto actual =
                  dfs(e->target, min(flow, capacities[e->id]))) {
            capacities[e->id] -= actual;
            capacities[e->reverse] += actual;
            return actual;
          }
        }
      }
      return 0;
    };
    auto result = 0;
    while (true) {
      const auto infinity = numeric_limits<int>::max();
      fill(begin(distances), end(distances), infinity);
      distances[source] = 0;
      auto queue = std::queue<int>({source});
      while (!queue.empty()) {
        const auto v = queue.front();
        queue.pop();
        for (const auto e : adjacency_list[v]) {
          if (capacities[e.id] && distances[e.target] == infinity) {
            distances[e.target] = distances[e.source] + 1;
            queue.push(e.target);
          }
        }
      }
      if (distances[sink] == infinity) break;
      for (auto v = 0; v < V; v++) cursors[v] = begin(adjacency_list[v]);
      while (const auto flow = dfs(source, numeric_limits<int>::max()))
        result += flow;
    }
    return result;
  };
};
int main() {
  ios::sync_with_stdio(false);
  auto network = Network();
  int n;
  cin >> n;
  auto vertices = array<vector<int>, 2>{};
  for (auto& vs : vertices) vs = vector<int>(4 * n);
  const function<int(int, int, int, bool)> build =
      [&](const int i, const int l, const int r, const bool direction) {
        const auto v = vertices[direction][i] = network.add_vertex();
        if (r - l == 1) {
          if (direction)
            network.add_edge(network.source, v, 1);
          else
            network.add_edge(v, network.sink, 1);
        } else {
          const auto m = (l + r) / 2;
          const auto w1 = build(2 * i, l, m, direction);
          const auto w2 = build(2 * i + 1, m, r, direction);
          if (direction) {
            network.add_edge(w1, v, n);
            network.add_edge(w2, v, n);
          } else {
            network.add_edge(v, w1, n);
            network.add_edge(v, w2, n);
          }
        }
        return v;
      };
  for (auto direction : {true, false}) build(1, 0, n, direction);
  using Segment = array<int, 2>;
  using Rectangle = array<Segment, 2>;
  const auto add_rectangle = [&](const Rectangle q) {
    if (q[0][0] == q[0][1] || q[1][0] == q[1][1]) return;
    const auto v = network.add_vertex();
    for (const auto direction : {true, false}) {
      const auto ql = q[direction][0], qr = q[direction][1];
      const function<void(int, int, int)> connect =
          [&](const int i, const int l, const int r) {
            if (ql >= r || l >= qr)
              return;
            else if (ql <= l && r <= qr) {
              if (direction)
                network.add_edge(vertices[direction][i], v, n);
              else
                network.add_edge(v, vertices[direction][i], n);
            } else {
              const auto m = (l + r) / 2;
              connect(2 * i, l, m);
              connect(2 * i + 1, m, r);
            }
          };
      connect(1, 0, n);
    }
  };
  int q;
  cin >> q;
  struct Event {
    bool type;
    int x;
    Segment y;
  };
  auto events = vector<Event>();
  for (auto i = 0; i < q; i++) {
    int x1, y1, x2, y2;
    cin >> x1 >> y1 >> x2 >> y2;
    x1--;
    y1--;
    x2--;
    y2--;
    events.push_back({true, x1, {y1, y2 + 1}});
    events.push_back({false, x2 + 1, {y1, y2 + 1}});
  }
  events.push_back({false, 0, {0, n}});
  events.push_back({true, n, {0, n}});
  const auto event_compare = [](const Event a, const Event b) {
    if (a.x != b.x)
      return a.x < b.x;
    else
      return a.type < b.type;
  };
  sort(begin(events), end(events), event_compare);
  struct PartialRectangle {
    int x1;
    Segment y;
  };
  const auto rect_compare = [](const PartialRectangle a,
                               const PartialRectangle b) {
    return a.y[0] < b.y[0];
  };
  auto active = set<PartialRectangle, decltype(rect_compare)>(rect_compare);
  for (const auto e : events) {
    if (e.type) {
      auto to_insert = vector<PartialRectangle>();
      auto i = active.lower_bound({0, e.y[0]});
      if (i != begin(active) && prev(i)->y[1] > e.y[0]) i = prev(i);
      while (i != end(active) && i->y[0] < e.y[1]) {
        if (i->y[0] < e.y[0]) to_insert.push_back({e.x, {i->y[0], e.y[0]}});
        if (e.y[1] < i->y[1]) to_insert.push_back({e.x, {e.y[1], i->y[1]}});
        add_rectangle({{{i->x1, e.x}, i->y}});
        active.erase(i++);
      }
      for (const auto r : to_insert) active.insert(r);
    } else
      active.insert({e.x, e.y});
  }
  cout << network.maxflow() << endl;
}
