#include <bits/stdc++.h>

using namespace std;
using int64 = long long;

constexpr int DEBUG = 0;

class RangeMaxTree {
 private:
  vector<int64> nodes;
  int num_nodes;

  // Returns the fold of overwrap between [node_l, node_r) and [l, r).
  // nodes[node_index] needs to correspond to [node_l, node_r).
  int64 GetRangeInternal(int node_index, int node_l, int node_r, int l, int r) {
    if (node_r <= l || r <= node_l) return INT64_MIN;
    if (l <= node_l && node_r <= r) return nodes[node_index];
    int node_m = (node_l + node_r) / 2;
    return max(
        GetRangeInternal(2 * node_index, node_l, node_m, l, r),
        GetRangeInternal(2 * node_index + 1, node_m, node_r, l, r));
  }

 public:
  // Arguments:
  // xs: The initial values.
  RangeMaxTree(const vector<int64>& xs) {
    int n = xs.size();
    num_nodes = 1;
    while (num_nodes < n) num_nodes *= 2;
    num_nodes *= 2;
    nodes = vector<int64>(num_nodes, INT64_MIN);
    for (int i = 0; i < xs.size(); ++i) {
      nodes[num_nodes / 2 + i] = xs[i];
    }
    for (int i = num_nodes / 2 - 1; i >= 1; i--) {
      nodes[i] = max(nodes[2 * i], nodes[2 * i + 1]);
    }
  }

  // Updates the i-th element to x.
  void Update(int i, int64 x) {
    nodes[num_nodes / 2 + i] = x;
    for (int cur = (num_nodes / 2 + i) / 2; cur > 0; cur /= 2) {
      nodes[cur] = max(nodes[2 * cur], nodes[2 * cur + 1]);
    }
  }

  // Returns the value of the range [l, r) merged by merge_fn.
  int64 RangeMax(int l, int r) {
    return GetRangeInternal(1, 0, num_nodes / 2, l, r);
  }

  int64 Get(int i) {
    return nodes[num_nodes / 2 + i];
  }
};

// Constraints:
// - is_upper_fn(l) = false.
// - is_upper_fn(u) = true.
// - is_upper_fn() is monotically increasing.
tuple<int, int> BinarySearch(int l, int u, function<bool(int)> is_upper_fn) {
  while (u - l >= 2) {
    int m = (l + u) / 2;
    if (is_upper_fn(m)) {
      u = m;
    } else {
      l = m;
    }
  }
  return {l, u};
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);

  function<int(int, int)> max_fn = [](int x, int y) {
    return max(x, y);
  };

  int n, q;
  cin >> n >> q;

  int64 ans = 0;

  RangeMaxTree r_tree(vector<int64>(n - 2, 0));
  RangeMaxTree c_tree(vector<int64>(n - 2, 0));
  for (int q_index = 0; q_index < q; q_index++) {
    int t;
    int x;
    cin >> t >> x;
    x -= 2;

    auto process_r_fn = [&] {
      int r = x;
      // if (c_tree.Get(0) >= r + 1) {
      //   return;
      // }
      if (c_tree.RangeMax(0, n - 2) <= r) {
        ans += n - 2;
        r_tree.Update(r, n - 2);
        return;
      }

      auto is_upper_fn = [&](int c) -> bool {
        return c_tree.RangeMax(0, c) >= r + 1;
      };
      int l = 0;
      int u = n - 2;
      // for (int i = l; i <= u; i++) {
      //   cout << c_tree.GetRange(0, i) << " " << is_upper_fn(i) << endl;
      // }
      tie(l, u) = BinarySearch(l, u, is_upper_fn);
      // cout << "l: " << l << " u: " << u << endl;
      ans += l;
      r_tree.Update(r, l);
    };

    auto process_c_fn = [&] {
      int c = x;
      // if (r_tree.Get(0) >= c + 1) {
      //   return;
      // }
      if (r_tree.RangeMax(0, n - 2) <= c) {
        ans += n - 2;
        c_tree.Update(c, n - 2);
        return;
      }

      auto is_upper_fn = [&](int r) -> bool {
        return r_tree.RangeMax(0, r) >= c + 1;
      };
      int l = 0;
      int u = n - 2;
      tie(l, u) = BinarySearch(l, u, is_upper_fn);
      ans += l;
      c_tree.Update(c, l);
    };

    if (t == 1) {
      process_c_fn();
    } else {
      process_r_fn();
    }

    // cout << "q_index: " << q_index << " " << ans << endl;
    // cout << "r_tree: ";
    // for (int i = 0; i < n - 2; i++) {
    //   cout << r_tree.Get(i) << " ";
    // }
    // cout << endl;
    // cout << "c_tree: ";
    // for (int i = 0; i < n - 2; i++) {
    //   cout << c_tree.Get(i) << " ";
    // }
    // cout << endl;
    // cout << endl;
  }

  // cout << ans << endl;
  cout << static_cast<int64>(n - 2) * (n - 2) - ans << endl;
}

Measured memory_bytes: 13012