#include <bits/stdc++.h>
using namespace std;

#define rep(i,n) for(i = 0;i < n;++i)
#define all(v) v.begin(), v.end()
using ll = long long;

template <typename T>
struct SegmentTreeLazy //デフォルトは区間変更区間合計
{
    int n;
    const T ex = 1 << 30; //dat 初期値(合計なので)
    const T em = 1 << 30; //lazy 初期値(updateするので)
    //lazyで一括更新をもって、datでqueryに対応する。weightはそのnodeが担当する下のnodeの数
    //lazyは上から下に伝搬する。datは区間で探して下から上にもらう。
    vector<T> dat, lazy, weight; //tree本体
    SegmentTreeLazy(vector<T> v){
        int x = 1;
        int i;
        n = v.size();
        while(x < n) x <<= 1;
        n = x; 
        dat.resize(2*n-1, ex); //tree本体
        lazy.resize(2*n-1, em); //遅延評価
        weight.resize(2*n-1, 0); //何node持ってるか
        for(i = 0;i < v.size();++i){
            dat.at(i + n - 1) = v.at(i);
            weight.at(i + n - 1) = 1;
        }
        for(i = n-2;i >= 0;--i){
            dat.at(i) = fx(dat.at(2*i+1), dat.at(2*i+2));
            weight.at(i) = weight.at(2*i + 1) + weight.at(2*i + 2);
        }
    }
    
    T fx(T a, T b){ //dat上での計算
        return min(a, b);
    }
    
    T fm(T a){ //lazy上での計算
        return min(a, em);
    }
    
    void eval(int now){ //区間下は全て影響を受ける。(受ける時しか呼ばれない)
        if(lazy.at(now) == em) return;
        if(now < n - 1){ //区間変更なので値を代入する。
            lazy.at(2*now + 1) = min(lazy.at(2*now + 1), lazy.at(now));
            lazy.at(2*now + 2) = min(lazy.at(2*now + 2), lazy.at(now));
        }
        //**********************ここが大事
        dat.at(now) = min(dat.at(now), lazy.at(now));
        //**********************
        lazy.at(now) = em;
    }
    
    void update(int a, int b, T x, int now, int l, int r){
        eval(now);
        if(a <= l && r<= b){ //区間内に全部いる。
            lazy.at(now) = min(lazy.at(now), x); //区間代入なので上から書き換える。
            eval(now);
        }else if(a < r && l < b){
            update(a, b, x, 2*now + 1, l, (l + r)/2);
            update(a, b, x, 2*now + 2, (l + r)/2, r);
            dat.at(now) = fx(dat.at(2*now + 1), dat.at(2*now + 2));
        }
    }
    void update(int a, int b, T x){update(a, b, x, 0, 0, n);}
    
    T query(int a, int b){return query_sub(a, b, 0, 0, n);}
    T query_sub(int a, int b, int now, int l, int r){
        eval(now);
        if(r <= a || b <= l) return ex;
        else if(a <= l && r <= b) return dat.at(now);
        else{
            T vl = query_sub(a, b, 2*now + 1, l, (l + r)/2);
            T vr = query_sub(a, b, 2*now + 2, (l + r)/2, r);
            return fx(vl, vr);
        }
    }
    
    inline T operator[](int a) { return query(a, a + 1); }
    void print() {
        for (int i = 0; i < 2 * n - 1; ++i) {
            cout << (*this)[i];
            if (i != n) cout << ",";
        }
        cout << endl;
    }
};

int main()
{
    int i,j;
    int n,q;
    cin >> n >> q;
    vector<int> ini(n, n-1);
    SegmentTreeLazy<int> tate(ini);
    SegmentTreeLazy<int> yoko(ini);
    ll ans = (ll)(n-2)*(ll)(n-2);
    rep(i,q){
        int c,x;
        cin >> c >> x;
        --x;
        if(c == 1){
            int tmp = tate.query(x, x+1);
            ans -= tmp-1;
            yoko.update(0, tmp+1, x);
        }else if(c == 2){
            int tmp = yoko.query(x, x+1);
            ans -= tmp-1;
            tate.update(0, tmp+1, x);
        }
    }
    cout << ans << endl;

    return 0;
}

Measured memory_bytes: 17216