// Slower C++ solution:
#include <bits/stdc++.h>

//#include <atcoder/all>

#define rep(i, a) for (int i = (int)0; i < (int)a; ++i)

#define rrep(i, a) for (int i = (int)a - 1; i >= 0; --i)

#define REP(i, a, b) for (int i = (int)a; i < (int)b; ++i)

#define RREP(i, a, b) for (int i = (int)a - 1; i >= b; --i)

#define pb push_back

#define eb emplace_back

#define all(x) x.begin(), x.end()

#define rall(x) x.rbegin(), x.rend()

#define popcount __builtin_popcount

using ll = long long;

constexpr ll mod = 1e9 + 7;

constexpr ll INF = 1LL << 60;



// #pragma GCC target("avx2")

// #pragma GCC optimize("O3")

// #pragma GCC optimize("unroll-loops")

template <class T>

inline bool chmin(T &a, T b)

{

	if (a > b)

	{

		a = b;

		return true;

	}

	return false;

}

template <class T>

inline bool chmax(T &a, T b)

{

	if (a < b)

	{

		a = b;

		return true;

	}

	return false;

}



ll gcd(ll n, ll m)

{

	ll tmp;

	while (m != 0)

	{

		tmp = n % m;

		n = m;

		m = tmp;

	}

	return n;

}



ll lcm(ll n, ll m)

{

	return abs(n) / gcd(n, m) * abs(m); //gl=xy

}



using namespace std;

//using namespace atcoder;





template<typename T>

struct LazySegmentTree{//区間更新,区間最小,0オリジン

    private:

        int n;

        vector<T>node,lazy;

        vector<bool>flag;

        const T inf=numeric_limits<T>::max();

    

    public:

        LazySegmentTree(vector<T>v){

            int sz=(int)v.size();//vをinfで初期化して渡すこと

            n=1;

            while(n<sz)n*=2;

            node.resize(2*n-1);

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

            flag.resize(2*n-1,false);



            for(int i=0;i<sz;i++)node[i+n-1]=v[i];

            for(int i=n-2;i>=0;--i)node[i]=min(node[2*i+1],node[2*i+2]);

        }



        //k番目のノードについて遅延評価

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

            //遅延配列が空でなければ値の伝播が起こる

            if(flag[k]){

                node[k]=lazy[k];



                if(r-l>1){//最下段かどうかの確認

                    lazy[2*k+1]=lazy[2*k+2]=lazy[k];

                    flag[2*k+2]=true,flag[2*k+1]=true;

                }



                flag[k]=0;

            }

        }



        void update(int a,int b,T x,int k=0,int l=0,int r=-1){

            if(r<0)r=n;



            //k番目のノードに遅延評価

            eval(k,l,r);



            //範囲外

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



            //完全に被覆しているなら遅延配列に代入した後に評価

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

                lazy[k]=x;

                flag[k]=true;

                eval(k,l,r);

            }



            //それ以外なら子ノードを再帰的に計算

            else{

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

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

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

            }

        }



        T getval(int a,int b,int k=0,int l=0,int r=-1){//区間和の取得

            if(r<0)r=n;



            eval(k,l,r);



            if(b<=l||r<=a)return inf;

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

            T vall=getval(a,b,2*k+1,l,(l+r)/2);

            T valr=getval(a,b,2*k+2,(l+r)/2,r);

            return min(vall,valr);

        }

};





void solve(){

	ll n,t;

	cin>>n>>t;

	vector<ll>v(n-2,n-2);

	LazySegmentTree<ll>row(v),clm(v);

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

	while(t--){

		ll q,x;

		cin>>q>>x;

		x-=2;

		if(q==1){

			ll val=clm.getval(x,x+1);

			ans-=val;

			if(row.getval(0,1)>x)row.update(0,val,x);

			clm.update(x,x+1,0);

		}

		else{

			ll val=row.getval(x,x+1);

			ans-=val;

			if(clm.getval(0,1)>x)clm.update(0,val,x);

			row.update(x,x+1,0);

		}

		// rep(i,n-2){

		// 	cout<<"row"<<row.getval(i,i+1)<<"\n";

		// 	cout<<"column"<<clm.getval(i,i+1)<<"\n";

		// }

		// cout<<"\n";

	}

	cout<<ans;

}





int main()

{

	ios::sync_with_stdio(false);

	cin.tie(0);

	cout << fixed << setprecision(15);

	solve();

	return 0;

}


// Faster C++ solution for the same problem (measured speedup: 1.2307505609189926x):
#include <bits/stdc++.h>

//#include <atcoder/all>

#define rep(i, a) for (int i = (int)0; i < (int)a; ++i)

#define rrep(i, a) for (int i = (int)a - 1; i >= 0; --i)

#define REP(i, a, b) for (int i = (int)a; i < (int)b; ++i)

#define RREP(i, a, b) for (int i = (int)a - 1; i >= b; --i)

#define pb push_back

#define eb emplace_back

#define all(x) x.begin(), x.end()

#define rall(x) x.rbegin(), x.rend()

#define popcount __builtin_popcount

using ll = long long;

constexpr ll mod = 1e9 + 7;

constexpr ll INF = 1LL << 60;



// #pragma GCC target("avx2")

// #pragma GCC optimize("O3")

// #pragma GCC optimize("unroll-loops")

template <class T>

inline bool chmin(T &a, T b)

{

	if (a > b)

	{

		a = b;

		return true;

	}

	return false;

}

template <class T>

inline bool chmax(T &a, T b)

{

	if (a < b)

	{

		a = b;

		return true;

	}

	return false;

}



ll gcd(ll n, ll m)

{

	ll tmp;

	while (m != 0)

	{

		tmp = n % m;

		n = m;

		m = tmp;

	}

	return n;

}



ll lcm(ll n, ll m)

{

	return abs(n) / gcd(n, m) * abs(m); //gl=xy

}



using namespace std;

//using namespace atcoder;



template< typename OperatorMonoid >

struct DuelSegmentTree {

  using H = function< OperatorMonoid(OperatorMonoid, OperatorMonoid) >;



  int sz, height;

  vector< OperatorMonoid > lazy;

  const H h;

  const OperatorMonoid OM0;





  DuelSegmentTree(int n, const H h, const OperatorMonoid OM0)

      : h(h), OM0(OM0) {

    sz = 1;

    height = 0;

    while(sz < n) sz <<= 1, height++;

    lazy.assign(2 * sz, OM0);

  }



  inline void propagate(int k) {

    if(lazy[k] != OM0) {

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

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

      lazy[k] = OM0;

    }

  }



  inline void thrust(int k) {

    for(int i = height; i > 0; i--) propagate(k >> i);

  }



  void update(int a, int b, const OperatorMonoid &x) {

    thrust(a += sz);

    thrust(b += sz - 1);

    for(int l = a, r = b + 1; l < r; l >>= 1, r >>= 1) {

      if(l & 1) lazy[l] = h(lazy[l], x), ++l;

      if(r & 1) --r, lazy[r] = h(lazy[r], x);

    }

  }



  OperatorMonoid operator[](int k) {

    thrust(k += sz);

    return lazy[k];

  }

};







void solve(){

	ll n,t;

	cin>>n>>t;

	DuelSegmentTree<ll>row(n-2,[](ll a,ll b){return min(a,b);},n-2),

										 clm(n-2,[](ll a,ll b){return min(a,b);},n-2);

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

	while(t--){

		ll q,x;

		cin>>q>>x;

		x-=2;

		if(q==1){

			ll val=clm.operator[](x);

			ans-=val;

			row.update(0,val,x);

			clm.update(x,x+1,0);

		}

		else{

			ll val=row.operator[](x);

			ans-=val;

			clm.update(0,val,x);

			row.update(x,x+1,0);

		}

	}

	cout<<ans;

}





int main()

{

	ios::sync_with_stdio(false);

	cin.tie(0);

	cout << fixed << setprecision(15);

	solve();

	return 0;

}