// Original C++ solution (slower):
// #define _GLIBCXX_DEBUG // for STL debug (optional)

#include <iostream>

#include <iomanip>

#include <cstdio>

#include <string>

#include <cstring>

#include <deque>

#include <list>

#include <queue>

#include <stack>

#include <vector>

#include <utility>

#include <algorithm>

#include <map>

#include <set>

#include <complex>

#include <cmath>

#include <limits>

#include <cfloat>

#include <climits>

#include <ctime>

#include <cassert>

#include <numeric>

#include <fstream>

#include <functional>

#include <bitset>

using namespace std;

using ll = long long int;

using int64 = long long int;

 

template<typename T> void chmax(T &a, T b) {a = max(a, b);}

template<typename T> void chmin(T &a, T b) {a = min(a, b);}

template<typename T> void chadd(T &a, T b) {a = a + b;}

 

int dx[] = {0, 0, 1, -1};

int dy[] = {1, -1, 0, 0};

const int INF = 1LL << 29;

const ll LONGINF = 1LL << 60;

const ll MOD = 1000000007LL;



// @category セグメント木 (Segment Tree)

// @title 遅延伝播セグメント木 (Lazy Segment Tree)

template <typename MonoidType, typename OperatorType>

struct LazySegmentTree {

    using MMtoM = function< MonoidType(MonoidType, MonoidType) >;

    using OOtoO = function< OperatorType(OperatorType, OperatorType) >;

    using MOtoM = function< MonoidType(MonoidType, OperatorType) >;

    using OItoO = function< OperatorType(OperatorType, int) >;



    // node, lazy, update flag (for lazy), identity element

    int n;

    vector<MonoidType> node;

    vector<OperatorType> lazy;

    vector<bool> need_update;

    MonoidType E0;

    OperatorType E1;



    // update / combine / lazy / accumulate function

    MOtoM upd_f;

    MMtoM cmb_f;

    OOtoO lzy_f;

    OItoO acc_f;



    void build(int m, vector<MonoidType> v = vector<MonoidType>()) {

        if(v != vector<MonoidType>()) m = v.size();

        n = 1; while(n < m) n *= 2;



        node = vector<MonoidType>(2*n-1, E0);

        lazy = vector<OperatorType>(2*n-1, E1);

        need_update = vector<bool>(2*n-1, false);

        if(v != vector<MonoidType>()) {

            for(int i=0; i<m; i++) {

                node[n-1+i] = v[i];

            }

            for(int i=n-2; i>=0; i--) {

                node[i] = cmb_f(node[2*i+1], node[2*i+2]);

            }

        }

    }



    // initialize

    LazySegmentTree() {}

    LazySegmentTree(int n_, MonoidType E0_, OperatorType E1_,

                    MOtoM upd_f_, MMtoM cmb_f_, OOtoO lzy_f_, OItoO acc_f_,

                    vector<MonoidType> v = vector<MonoidType>()) :

        E0(E0_), E1(E1_),

        upd_f(upd_f_), cmb_f(cmb_f_), lzy_f(lzy_f_), acc_f(acc_f_) {

        build(n_, v);

    }



    void eval(int k, int l, int r) {

        if(!need_update[k]) return;

        node[k] = upd_f(node[k], acc_f(lazy[k], r - l));

        if(r - l > 1) {

            lazy[2*k+1] = lzy_f(lazy[2*k+1], lazy[k]);

            lazy[2*k+2] = lzy_f(lazy[2*k+2], lazy[k]);

            need_update[2*k+1] = need_update[2*k+2] = true;

        }

        lazy[k] = E1;

        need_update[k] = false;

    }



    void update(int a, int b, OperatorType x, int l, int r, int k) {

        eval(k, l, r);

        if(b <= l or  r <= a) return;

        if(a <= l and r <= b) {

            lazy[k] = lzy_f(lazy[k], x);

            need_update[k] = true;

            eval(k, l, r);

        }

        else {

            int mid = (l + r) / 2;

            update(a, b, x, l, mid, 2*k+1);

            update(a, b, x, mid, r, 2*k+2);

            node[k] = cmb_f(node[2*k+1], node[2*k+2]);

        }

    }



    MonoidType query(int a, int b, int l, int r, int k) {

        if(b <= l or  r <= a) return E0;

        eval(k, l, r);

        if(a <= l and r <= b) return node[k];

        int mid = (l + r) / 2;

        MonoidType vl = query(a, b, l, mid, 2*k+1);

        MonoidType vr = query(a, b, mid, r, 2*k+2);

        return cmb_f(vl, vr);

    }



    // update [a, b)-th element (applied value, x)

    void update(int a, int b, OperatorType x) {

        update(a, b, x, 0, n, 0);

    }



    // range query for [a, b)

    MonoidType query(int a, int b) {

        return query(a, b, 0, n, 0);

    }



    void dump() {

        fprintf(stderr, "[lazy]\n");

        for(int i=0; i<2*n-1; i++) {

            if(i == n-1) fprintf(stderr, "xxx ");

            if(lazy[i] == E1) fprintf(stderr, "  E ");

            else fprintf(stderr, "%3d ", lazy[i]);

        }

        fprintf(stderr, "\n");



        fprintf(stderr, "[node]\n");

        for(int i=0; i<2*n-1; i++) {

            if(i == n-1) fprintf(stderr, "xxx ");

            if(node[i] == E0) fprintf(stderr, "  E ");

            else fprintf(stderr, "%3d ", node[i]);

        }

        fprintf(stderr, "\n");

    }

};



int main() {

    int N, Q; scanf("%d%d", &N, &Q);



    // 区間加算, 区間 min, 区間更新をサポート

    using Tp = pair<ll, ll>;

    const Tp E(0, INF);

    LazySegmentTree< Tp, Tp > sx(N, E, E,

                                 [](Tp a, Tp b) {

                                     return make_pair(

                                         b.first, min(a.second, b.second)

                                         );

                                 },

                                 [](Tp a, Tp b) {

                                     return make_pair(

                                         a.first+b.first, min(a.second, b.second)

                                         );                                     

                                 },

                                 [](Tp a, Tp b) {

                                     return make_pair(

                                         b.first, min(a.second, b.second)

                                         );

                                 },

                                 [](Tp a, int x) {

                                     return make_pair(

                                         a.first*x, a.second

                                         );

                                 },

                                 vector<Tp>(N-2, make_pair(N-2, N-2))

        );

    LazySegmentTree< Tp, Tp > sy = sx;



    ll ans = 1LL * (N-2) * (N-2);

    while(Q--) {

        int t, x; scanf("%d%d", &t, &x);

        x -= 2;

        LazySegmentTree<Tp, Tp> &s1 = (t == 1 ? sx : sy);

        LazySegmentTree<Tp, Tp> &s2 = (t == 2 ? sx : sy);

        // s1 は一点だけ 0 になる

        // s2 は [0, i) を更新 (i は x 以下になる最初の値)

        // 0 ... N-3 (N-2 要素)

        int ub = N-2, lb = -1;

        while(ub - lb > 1) {

            int mid = (ub + lb) / 2;

            if(s2.query(0, mid+1).second <= x) ub = mid;

            else lb = mid;

        }

        // ub をいれると x 未満になってしまう

        ans -= s1.query(x, x+1).first;

        s2.update(0, ub, make_pair(x, x));

        s1.update(x, x+1, make_pair(0, 0));



        /*

        fprintf(stderr, "# ans = %lld\n", ans);

        fprintf(stderr, "sx:");

        for(int i=0; i<N-2; i++) {

            auto p = sx.query(i, i+1);

            fprintf(stderr, " [%lld, %lld]", p.first, p.second);

        }

        fprintf(stderr, "\n");

        fprintf(stderr, "sy:");

        for(int i=0; i<N-2; i++) {

            auto p = sy.query(i, i+1);

            fprintf(stderr, " [%lld, %lld]", p.first, p.second);

        }

        fprintf(stderr, "\n\n");

        */

    }

    printf("%lld\n", ans);

    return 0;

}


// Optimized solution to the same problem (faster):
// #define _GLIBCXX_DEBUG // for STL debug (optional)

#include <iostream>

#include <iomanip>

#include <cstdio>

#include <string>

#include <cstring>

#include <deque>

#include <list>

#include <queue>

#include <stack>

#include <vector>

#include <utility>

#include <algorithm>

#include <map>

#include <set>

#include <complex>

#include <cmath>

#include <limits>

#include <cfloat>

#include <climits>

#include <ctime>

#include <cassert>

#include <numeric>

#include <fstream>

#include <functional>

#include <bitset>

using namespace std;

using ll = long long int;

using int64 = long long int;

 

template<typename T> void chmax(T &a, T b) {a = max(a, b);}

template<typename T> void chmin(T &a, T b) {a = min(a, b);}

template<typename T> void chadd(T &a, T b) {a = a + b;}

 

int dx[] = {0, 0, 1, -1};

int dy[] = {1, -1, 0, 0};

const int INF = 1LL << 29;

const ll LONGINF = 1LL << 60;

const ll MOD = 1000000007LL;



int main() {

    int N, Q; scanf("%d%d", &N, &Q);

    vector< vector<int> > b(2, vector<int>(N, -1));

    vector<int> p(2, N-2);

    ll ans = 1LL * (N-2) * (N-2);

    while(Q--) {

        int t, x; scanf("%d%d", &t, &x);

        t--; x -= 2; // x is 0-indexed

        if(b[t][x] != -1) {

            ans -= b[t][x];

        }

        else {

            ans -= p[t^1];

            for(int a=x+1; a<p[t]; a++) b[t][a] = p[t^1];

            p[t] = x;

        }

    }

    printf("%lld\n", ans);

}


// Fastest known solution for this problem: