#include <bits/stdc++.h>
//#include <chrono>
//#pragma GCC optimize("Ofast")
using namespace std;
#define reps(i,s,n) for(int i = s; i < n; i++)
#define rep(i,n) reps(i,0,n)
#define Rreps(i,n,e) for(int i = n - 1; i >= e; --i)
#define Rrep(i,n) Rreps(i,n,0)
#define ALL(a) a.begin(), a.end()
#define fi first
#define se second

using ll = long long;
using vec = vector<ll>;
using mat = vector<vec>;

ll N,M,H,W,Q,K,A,B;
string S;
typedef pair<ll, ll> P;
const ll INF = (1LL<<60);

template <class T> class SEGTREE {
    unsigned int n;
    T dflt, cmp;
    vector<T> dat;

    static T op(const T a, const T b) {
        return max(a, b);
    }

    bool f(const T &a){
        return a >= cmp;
    }

public:
    SEGTREE(unsigned long _n, T _a) : n(1), dflt(_a) {
        while (n < _n) {n *= 2;}
        dat.resize(n * 2, dflt);
    }

    void update(unsigned int k, T a) {
        k += n;
        dat[k] = a;
        while (k > 0) {
            k >>= 1;
            dat[k] = op(dat[k<<1], dat[(k<<1)|1]);
        }
    }

    void init(vector<T> &v) {
        for (int i = 0; i < (int)v.size(); ++i) dat[i + n] = v[i];
        for (int i = n - 1; i >= 1; --i) {
            dat[i] = op(dat[i * 2], dat[i * 2 + 1]);
        }
    }

    T query(unsigned int l, unsigned int r) {
        T res_left = dflt, res_right = dflt;
        l += n; r += n;
        for ( ; l < r; l >>= 1, r >>= 1){
            if(l&1){
                res_left = op(res_left, dat[l]);
                if((++l) == r) break;
            }
            if(r&1){
                res_right = op(dat[r ^ 1], res_right);
            }
        }
        return op(res_left, res_right);
    }

    unsigned int max_right_search(unsigned int id, T &total){
        while(id < n) {
            id <<= 1;
            if(!f(op(total, dat[id]))){
                total = op(total, dat[id]);
                id |= 1;
            }
        }
        return id - n;
    }

    unsigned int max_right(unsigned int l, unsigned int r, T &a){
        //定義：op( dat[i], ..., dat[j - 1] ) = false
        //      op( dat[i], ..., dat[j] ) = true      となるjを返す(単調性を仮定)
        //op = maxの場合、[l, r)内のindexであるjであって、query(l, j) < a <= query(l, j + 1)なるものを求める
        //つまり、j >= l かつ dat[j] >= a である最小の数jを求める
        cmp = a;
        l += n;
        vector<unsigned int> right_id(0);
        T total(dflt);
        for (unsigned int tr = r + n ; l < tr; l >>= 1, tr >>= 1){
            if(l&1){
                if(f(op(total, dat[l]))) return max_right_search(l, total);
                total = op(total, dat[l]);
                if((++l) == tr) break;
            }
            if(tr&1) right_id.push_back(tr ^ 1);
        }
        for(auto ite = right_id.rbegin(); ite != right_id.rend(); ++ite){
            if(f(op(total, dat[*ite]))) return max_right_search(*ite, total);
            total = op(total, dat[*ite]);
        }
        return r;
    }

    //単項にアクセスする[]だが、書き換え厳禁
    //一応後でinitすれば書き換えてもよさそうだが…
    ll &operator[](int k) { return dat[k + n]; }
};

int main() {
    cin>>N>>Q;
    N -= 2;
    SEGTREE<ll> yoko(N + 5, -1), tate(N + 5, -1);
    ll res(N * N);
    rep(_, Q){
        int t;
        ll x;
        cin>>t>>x;
        x -= 2;
        if(t == 2) swap(yoko, tate);
        int id = tate.max_right(0, N, x);
        res -= id;
        yoko.update(x, id);
        if(t == 2) swap(yoko, tate);
    }
    cout<<res<<endl;
}


Measured memory_bytes: 11368