// Original C++ solution (slower):
#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 RUQ //calculateはminimum

{

    int n;

    const T ex = 1ll << 60; //dat 初期値(minなので)

    const T em = 1ll << 60; //lazy 初期値(minなので)

    vector<T> dat, lazy; //tree本体

    RUQ(vector<T> v){

        int x = 1;

        int i;

        n = v.size();

        while(x < n) x <<= 1;

        n = x; 

        dat.resize(2*n-1, ex);

        lazy.resize(2*n-1, em);

        for(i = 0;i < v.size();++i){

            dat.at(i + n - 1) = v.at(i);

        }

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

            dat.at(i) = calculate(dat.at(2*i+1), dat.at(2*i+2));

        }

    }

    

    T calculate(T a, T b){

        return min(a, b); //minで使う

    }

    

    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) = calculate(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 calculate(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()

{

    ll i,j;

    ll n,q;

    cin >> n >> q;

    vector<ll> ini(n, n-1);

    RUQ<ll> tate(ini);

    RUQ<ll> yoko(ini);

    ll ans = (n-2)*(n-2);

    rep(i,q){

        ll c,x;

        cin >> c >> x;

        --x;

        if(c == 1){

            ll tmp = tate.query(x, x+1);

            ans -= tmp-1;

            yoko.update(0, tmp+1, x);

        }else if(c == 2){

            ll tmp = yoko.query(x, x+1);

            ans -= tmp-1;

            tate.update(0, tmp+1, x);

        }

    }

    cout << ans << endl;



    return 0;

}

// Optimized solution to the same problem (faster):
#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; //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); //遅延評価

        for(i = 0;i < v.size();++i){

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

        }

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

            dat[i] = fx(dat[2*i+1], dat[2*i+2]);

        }

    }

    

    T fx(T a, T b){ //dat上での計算

        return min(a, b);

    }

    

    void eval(int now){ //区間下は全て影響を受ける。(受ける時しか呼ばれない)

        if(lazy[now] == em) return;

        if(now < n - 1){ //区間変更なので値を代入する。

            lazy[2*now + 1] = min(lazy[2*now + 1], lazy[now]);

            lazy[2*now + 2] = min(lazy[2*now + 2], lazy[now]);

        }

        //**********************ここが大事

        dat[now] = min(dat[now], lazy[now]);

        //**********************

        lazy[now] = em;

    }

    

    void update(int a, int b, T x, int now, int l, int r){

        eval(now);

        if(a <= l && r<= b){ //区間内に全部いる。

            lazy[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[2*now + 1], dat[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;

}

// Fastest known solution for this problem: