Problem:
Score : 600 points

Problem Statement

There is a grid with N rows and N columns of squares. Let (i, j) be the square at the i-th row from the top and the j-th column from the left.

Each of the central (N-2) \times (N-2) squares in the grid has a black stone on it.
Each of the 2N - 1 squares on the bottom side and the right side has a white stone on it.

Q queries are given. We ask you to process them in order.
There are two kinds of queries. Their input format and description are as follows:

1 x: Place a white stone on (1, x). After that, for each black stone between (1, x) and the first white stone you hit if you go down from (1, x), replace it with a white stone.

2 x: Place a white stone on (x, 1). After that, for each black stone between (x, 1) and the first white stone you hit if you go right from (x, 1), replace it with a white stone.

How many black stones are there on the grid after processing all Q queries?

Constraints

3 \leq N \leq 2\times 10^5

0 \leq Q \leq \min(2N-4,2\times 10^5)

2 \leq x \leq N-1

Queries are pairwise distinct.

Input

Input is given from Standard Input in the following format:

N Q
Query_1
\vdots
Query_Q

Output

Print how many black stones there are on the grid after processing all Q queries.

Sample Input 1

5 5
1 3
2 3
1 4
2 2
1 2

Sample Output 1

1

After each query, the grid changes in the following way:

Sample Input 2

200000 0

Sample Output 2

39999200004

Sample Input 3

176527 15
1 81279
2 22308
2 133061
1 80744
2 44603
1 170938
2 139754
2 15220
1 172794
1 159290
2 156968
1 56426
2 77429
1 97459
2 71282

Sample Output 3

31159505795

Solution in C++ (GCC 9.2.1) (judge verdict: Accepted)

#include <bits/stdc++.h>
#define REP(i,n) for(int i=0;i<(n);++i)
#define ALL(v)   (v).begin(),(v).end()
#define debug(x) cerr<<#x<<": "<<(x)<<endl
using namespace std;
using llong = long long;
using vi    = vector<int>;
using vvi   = vector<vi >;
using vvvi  = vector<vvi >;
using pii   = pair<int,int>;
constexpr int    INF=1e9;
constexpr double EPS=1e-9;
constexpr int    MOD=1e9+7;
template<class Type>
void line(const Type &a){int cnt=0;for(const auto &elem:a){cerr<<(cnt++?' ':'>');cerr<<elem;}cerr<<endl;}

/*遅延評価セグメント木*/
template<typename T,typename U=T>
class LazySegmentTree{
	using FX=function<T(T,T)>;
	using FA=function<T(T,U)>;
	using FM=function<U(U,U)>;
	using FP=function<U(U,int)>;
	int n,offset;	//n:=(数列の数（2の階乗数)),offset:=(オフセット（n-1）).
	const T ex;		//ex:=(モノイドXの単位元).
	const U em;		//em:=(モノイドMの単位元).
	vector<T> node;
	vector<U> lazy;
	const FX fx;	//fx:=(X ✕ X->X).　比較用.
	const FA fa;	//fa:=(X ✕ M->X). 更新用.
	const FM fm;	//fa:=(M ✕ M->M). 遅延分比較用（基本fxと同じ）.
	const FP fp;	//fp:=(写像).
	
	int bufsize(int n_){//木に必要なノード数を返す.
		n=1;
		while(n<n_) n<<=1;
		offset=n-1;
		return 2*n-1;
	}
	void build(int l=0,int r=-1){//木を構築する. O(N).
		if(r<0) r=n;
		l+=offset, r+=offset;
		do{
			l=(l-1)/2, r=(r-1)/2;
			for(int i=l;i<r;++i) node[i]=fx(node[2*i+1],node[2*i+2]);
		}while(l>0);
	}
	void eval(int k,int l,int r){//k番目のノードについて遅延評価する.
		if(lazy[k]==em) return;
		node[k]=fa(node[k],fp(lazy[k],r-l));
		if(k<offset){//葉でなければ子に伝搬.
			lazy[2*k+1]=fm(lazy[2*k+1],lazy[k]);
			lazy[2*k+2]=fm(lazy[2*k+2],lazy[k]);
		}
		lazy[k]=em;
	}
	
public:
	/*constructor.*/
	LazySegmentTree(int n_,T ex_,U em_,FX fx_,FA fa_,FM fm_,FP fp_)
	:ex(ex_),em(em_),fx(fx_),fa(fa_),fm(fm_),fp(fp_){
		int sz=bufsize(n_);
		node.assign(sz,ex), lazy.assign(sz,em);
	}
	LazySegmentTree(const vector<T> &v_,T ex_,U em_,FX fx_,FA fa_,FM fm_,FP fp_)
	:ex(ex_),em(em_),fx(fx_),fa(fa_),fm(fm_),fp(fp_){
		int sz=bufsize(v_.size());
		node.assign(sz,ex), lazy.assign(sz,em);
		copy(ALL(v_),node.begin()+offset);//<algorithm>.
		build();
	}
	
	void init(){fill(ALL(node),ex), fill(ALL(lazy),em);}//初期化する.
	void update(int a,int b,T x,int k=0,int l=0,int r=-1){//[a,b)間の要素をaに更新する. O(log N).
		if(r<0) r=n;
		eval(k,l,r);
		if(b<=l or r<=a) return;
		if(a<=l and r<=b){
			lazy[k]=fm(lazy[k],x);
			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]=fx(node[2*k+1],node[2*k+2]);
		}
	}
	/*[a,b)間のクエリ結果を返す. O(log N).
	（後ろの3つの引数は計算の簡単のための引数. kは節点の番号,lとrはその節点が[l,r)に対応づいているかを表す. したがって,外からはquery(a,b,0,0,n)と呼ぶ.）*/
	T query(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 or r<=a) return ex;			//[a,b)と[l,r)が交差しなければex.
		if(a<=l and r<=b) return node[k];	//[a,b)が[l,r)を完全に含んでいれば,この節点の値.
		T vl=query(a,b,2*k+1,l,(l+r)/2);
		T vr=query(a,b,2*k+2,(l+r)/2,r);
		return fx(vl,vr);					//交差する場合,2つの子をクエリ処理して比較.
	}
	
	typename vector<T>::reference operator[](int i){return node[i+offset];}
};

int main(){
	int n,q;
	cin>>n>>q;
	
	using Type=int;
	auto fx=[](Type a,Type b)->Type{return (a<b?a:b);};//比較用.
	auto fa=[](Type a,Type b)->Type{return (a<b?a:b);};//更新用.
	auto fm=[](Type a,Type b)->Type{return (a<b?a:b);};//遅延分比較用（基本fxと同じ）.
	auto fp=[](Type a,int len)->Type{return a;};//写像.
	LazySegmentTree<Type> y(n,n-1,n-1,fx,fa,fm,fp);//それぞれのラインで最もレーンが近い位置.
	LazySegmentTree<Type> x(n,n-1,n-1,fx,fa,fm,fp);
	
	llong ans=(llong)(n-2)*(n-2);
	REP(i,q){
		int t,p;
		cin>>t>>p;
		p--;
		
		if(t==1){
			int u=1, l=x.query(p,p+1);
			//debug(l);
			ans-=l-u;
			y.update(0,l,p);
		}else{
			int l=1, r=y.query(p,p+1);
			//debug(r);
			ans-=r-l;
			x.update(0,r,p);
		}
		//debug(ans);
	}
	
	cout<<ans<<endl;
	return 0;
}