// Caching the results of the unchanged blocks.
// On my machine the previous hack test only take <4s to run.
//
// Also special-case some cases int get function so the time complexity is only O(1), not O(log n).
// I don't know if this is an optimization or deoptimization.

#ifndef LOCAL
#define NDEBUG
#endif
#include<array>
#include<cassert>
#include<algorithm>
#include<climits>
#include<cstdio>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
namespace io{using namespace std;static const int buf_size=4096;static unsigned char buf[buf_size];static int buf_len=0,buf_pos=0;inline bool isEof(){if(buf_pos==buf_len){buf_pos=0,buf_len=fread(buf,1,buf_size,stdin);if(buf_pos==buf_len)return 1;}return 0;}inline int getChar(){return isEof()?-1:buf[buf_pos++];}inline int peekChar(){return isEof()?-1:buf[buf_pos];}inline bool seekEof(){int c;while((c=peekChar())!=-1&&c<=32)buf_pos++;return c==-1;}inline void skipBlanks(){while(!isEof()&&buf[buf_pos]<=32U)buf_pos++;}inline int readChar(){int c=getChar();while(c!=-1&&c<=32)c=getChar();return c;}inline int readUInt(){int c=readChar(),x=0;while('0'<=c&&c<='9')x=x*10+c-'0',c=getChar();return x;}template<class T=int>inline T readInt(){int s=1,c=readChar();T x=0;if(c=='-')s=-1,c=getChar();else if(c=='+')c=getChar();while('0'<=c&&c<='9')x=x*10+c-'0',c=getChar();return s==1?x:-x;}inline double readDouble(){int s=1,c=readChar();double x=0;if(c=='-')s=-1,c=getChar();while('0'<=c&&c<='9')x=x*10+c-'0',c=getChar();if(c=='.'){c=getChar();double coef=1;while('0'<=c&&c<='9')x+=(c-'0')*(coef*=1e-1),c=getChar();}return s==1?x:-x;}inline void readWord(char*s){int c=readChar();while(c>32)*s++=c,c=getChar();*s=0;}inline bool readLine(char*s){int c=getChar();while(c!='\n'&&c!=-1)*s++=c,c=getChar();*s=0;return c!=-1;}static int write_buf_pos=0;static char write_buf[buf_size];inline void writeChar(int x){if(write_buf_pos==buf_size)fwrite(write_buf,1,buf_size,stdout),write_buf_pos=0;write_buf[write_buf_pos++]=x;}inline void flush(){if(write_buf_pos){fwrite(write_buf,1,write_buf_pos,stdout),write_buf_pos=0;fflush(stdout);}}template<class T>inline void writeInt(T x,char end=0,int output_len=-1){if(x<0)writeChar('-'),x=-x;char s[24];int n=0;while(x||!n)s[n++]='0'+x%10,x/=10;while(n<output_len)s[n++]='0';while(n--)writeChar(s[n]);if(end)writeChar(end);}inline void writeWord(const char*s){while(*s)writeChar(*s++);}inline void writeDouble(double x,int output_len=0){if(x<0)writeChar('-'),x=-x;int t=(int)x;writeInt(t),x-=t;writeChar('.');for(int i=output_len-1;i>0;i--){x*=10;t=std::min(9,(int)x);writeChar('0'+t),x-=t;}x*=10;t=std::min(9,(int)(x+0.5));writeChar('0'+t);}static struct buffer_flusher_t{~buffer_flusher_t(){flush();}}buffer_flusher;};
#pragma GCC diagnostic pop

#include<vector>

int const BLOCKSIZE=1000;

struct block{
	struct interval{ // inclusive
		int l,r;
	};
	std::vector<interval> d;
	int min,max;

	template<class Iter>
	void recompute(Iter first,Iter last){
		assert(last-first<=BLOCKSIZE+1);
		assert(last-first>=2);

		std::array<int,BLOCKSIZE+1> minpre,maxsuf;
		d.reserve(last-first-1);
		d.clear();

		min=*first;
		for(int i=0;first+i!=last;++i)
			minpre[i]=min=std::min(min,first[i]);

		max=last[-1];
		for(auto i=last-first;i--;)
			maxsuf[i]=max=std::max(max,first[i]);

		for(auto i=last-first-1;i;--i){
			assert(minpre[i-1]!=maxsuf[i]);
			if(minpre[i-1]>maxsuf[i])
				d.push_back({maxsuf[i],minpre[i-1]});
		}

		assert(std::is_sorted(begin(d),end(d),[](interval x,interval y){
					return x.l<y.l;
					}));
	} // only O(n)

	int get(int minpre,int maxsuf)const{
		if(minpre<maxsuf or d.empty())return 0;
		assert(minpre>maxsuf);
		auto const cond1=[](interval x,int y){return x.l<=y;};
		auto max_iter=cond1(d.back(),minpre) ? end(d) : std::lower_bound(begin(d),end(d),minpre,cond1);

		auto const cond2=[](interval x,int y){return x.r<y;};
		auto min_iter=cond2(d[0],maxsuf) ? begin(d) : std::lower_bound(begin(d),max_iter,maxsuf,cond2);

		return max_iter-min_iter;
		// number of segments that intersect [maxsuf..minpre]
	}
};

int main(){
	int n=io::readUInt();
	int nquery=io::readUInt();
	std::vector<int> a(n);
	std::generate(begin(a),end(a),io::readUInt);

	std::vector<block> blocks;
	for(int i=0;n-i*BLOCKSIZE>=2;++i){
		blocks.emplace_back();
		blocks[i].recompute(begin(a)+i*BLOCKSIZE,
				begin(a)+std::min((int)a.size(),i*BLOCKSIZE+BLOCKSIZE+1));
	}
	// NOTE one update may modify at most 2 block

	std::vector<int> maxsuf(blocks.size()+1);

	std::vector<int> minpre(blocks.size()+1); // exclusive

	auto const recompute_minmax=[&](){
		maxsuf.back()=INT_MIN;
		for(auto blocki=blocks.size();blocki--;)
			maxsuf[blocki]=std::max(maxsuf[blocki+1],blocks[blocki].max);

		minpre[0]=INT_MAX;
		for(auto blocki=1;blocki<=blocks.size();++blocki)
			minpre[blocki]=std::min(minpre[blocki-1],blocks[blocki-1].min);
	};
	recompute_minmax();

	int out=0;
	for(unsigned blocki=0;blocki<blocks.size();++blocki)
		out+=blocks[blocki].get(minpre[blocki],maxsuf[blocki+1]);

	while(nquery--){
		int pos=io::readUInt()-1;
		int x=io::readUInt();

		assert(x!=a[pos]);
		a[pos]=x;

		auto mincblock=pos==0 ? 0 : (pos-1)/BLOCKSIZE;
		auto maxcblock=std::min(int(blocks.size()-1),pos/BLOCKSIZE);

		auto const old_minpre=minpre;
		auto const old_maxsuf=maxsuf;

		recompute_minmax();

		for(int blocki=0;blocki<(int)blocks.size();++blocki)
			if(old_minpre[blocki]!=minpre[blocki] or old_maxsuf[blocki]!=maxsuf[blocki] or
					(mincblock<=blocki and blocki<=maxcblock))
				out-=blocks[blocki].get(old_minpre[blocki],old_maxsuf[blocki+1]);

		for(int blocki=mincblock;blocki<=maxcblock;++blocki)
			blocks[blocki].recompute(begin(a)+blocki*BLOCKSIZE,
					begin(a)+std::min((int)a.size(),blocki*BLOCKSIZE+BLOCKSIZE+1));

		for(int blocki=0;blocki<(int)blocks.size();++blocki)
			if(old_minpre[blocki]!=minpre[blocki] or old_maxsuf[blocki]!=maxsuf[blocki] or
					(mincblock<=blocki and blocki<=maxcblock))
				out+=blocks[blocki].get(minpre[blocki],maxsuf[blocki+1]);

		io::writeInt(out+1 /* nblock = nsplit+1 */);
		io::writeChar('\n');
	}
}


// I think I knew what the bug is, but I don't believe this will pass the time limit.
#ifndef LOCAL
#define NDEBUG
#endif
#include<array>
#include<cassert>
#include<algorithm>
#include<climits>
#include<cstdio>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
namespace io{using namespace std;static const int buf_size=4096;static unsigned char buf[buf_size];static int buf_len=0,buf_pos=0;inline bool isEof(){if(buf_pos==buf_len){buf_pos=0,buf_len=fread(buf,1,buf_size,stdin);if(buf_pos==buf_len)return 1;}return 0;}inline int getChar(){return isEof()?-1:buf[buf_pos++];}inline int peekChar(){return isEof()?-1:buf[buf_pos];}inline bool seekEof(){int c;while((c=peekChar())!=-1&&c<=32)buf_pos++;return c==-1;}inline void skipBlanks(){while(!isEof()&&buf[buf_pos]<=32U)buf_pos++;}inline int readChar(){int c=getChar();while(c!=-1&&c<=32)c=getChar();return c;}inline int readUInt(){int c=readChar(),x=0;while('0'<=c&&c<='9')x=x*10+c-'0',c=getChar();return x;}template<class T=int>inline T readInt(){int s=1,c=readChar();T x=0;if(c=='-')s=-1,c=getChar();else if(c=='+')c=getChar();while('0'<=c&&c<='9')x=x*10+c-'0',c=getChar();return s==1?x:-x;}inline double readDouble(){int s=1,c=readChar();double x=0;if(c=='-')s=-1,c=getChar();while('0'<=c&&c<='9')x=x*10+c-'0',c=getChar();if(c=='.'){c=getChar();double coef=1;while('0'<=c&&c<='9')x+=(c-'0')*(coef*=1e-1),c=getChar();}return s==1?x:-x;}inline void readWord(char*s){int c=readChar();while(c>32)*s++=c,c=getChar();*s=0;}inline bool readLine(char*s){int c=getChar();while(c!='\n'&&c!=-1)*s++=c,c=getChar();*s=0;return c!=-1;}static int write_buf_pos=0;static char write_buf[buf_size];inline void writeChar(int x){if(write_buf_pos==buf_size)fwrite(write_buf,1,buf_size,stdout),write_buf_pos=0;write_buf[write_buf_pos++]=x;}inline void flush(){if(write_buf_pos){fwrite(write_buf,1,write_buf_pos,stdout),write_buf_pos=0;fflush(stdout);}}template<class T>inline void writeInt(T x,char end=0,int output_len=-1){if(x<0)writeChar('-'),x=-x;char s[24];int n=0;while(x||!n)s[n++]='0'+x%10,x/=10;while(n<output_len)s[n++]='0';while(n--)writeChar(s[n]);if(end)writeChar(end);}inline void writeWord(const char*s){while(*s)writeChar(*s++);}inline void writeDouble(double x,int output_len=0){if(x<0)writeChar('-'),x=-x;int t=(int)x;writeInt(t),x-=t;writeChar('.');for(int i=output_len-1;i>0;i--){x*=10;t=std::min(9,(int)x);writeChar('0'+t),x-=t;}x*=10;t=std::min(9,(int)(x+0.5));writeChar('0'+t);}static struct buffer_flusher_t{~buffer_flusher_t(){flush();}}buffer_flusher;};
#pragma GCC diagnostic pop

#include<vector>

int const BLOCKSIZE=1000;

struct block{
	struct interval{ // inclusive
		int l,r;
	};
	std::vector<interval> d;
	int min,max;

	template<class Iter>
	void recompute(Iter first,Iter last){
		assert(last-first<=BLOCKSIZE+1);
		assert(last-first>=2);

		std::array<int,BLOCKSIZE+1> minpre,maxsuf;
		d.reserve(last-first-1);
		d.clear();

		min=*first;
		for(int i=0;first+i!=last;++i)
			minpre[i]=min=std::min(min,first[i]);

		max=last[-1];
		for(auto i=last-first;i--;)
			maxsuf[i]=max=std::max(max,first[i]);

		for(auto i=last-first-1;i;--i){
			assert(minpre[i-1]!=maxsuf[i]);
			if(minpre[i-1]>maxsuf[i])
				d.push_back({maxsuf[i],minpre[i-1]});
		}

		assert(std::is_sorted(begin(d),end(d),[](interval x,interval y){
					return x.l<y.l;
					}));
	} // only O(n)

	int get(int minpre,int maxsuf)const{
		if(minpre<maxsuf)return 0;
		assert(minpre>maxsuf);
		return int(
			std::lower_bound(begin(d),end(d),minpre,[](interval x,int y){return x.l<=y;})
			-
			std::lower_bound(begin(d),end(d),maxsuf,[](interval x,int y){return x.r<y;})
			);
		// number of segments that intersect [maxsuf..minpre]
	}
};

int main(){
	int n=io::readUInt();
	int nquery=io::readUInt();
	std::vector<int> a(n);
	std::generate(begin(a),end(a),io::readUInt);

	std::vector<block> blocks;
	for(int i=0;n-i*BLOCKSIZE>=2;++i){
		blocks.emplace_back();
		blocks[i].recompute(begin(a)+i*BLOCKSIZE,
				begin(a)+std::min((int)a.size(),i*BLOCKSIZE+BLOCKSIZE+1));
	}
	// NOTE one update may modify at most 2 block

	while(nquery--){
		int pos=io::readUInt()-1;
		int x=io::readUInt();

		assert(x!=a[pos]);
		a[pos]=x;

		for(int blocki=(pos==0 ? 0 : (pos-1)/BLOCKSIZE);
				blocki<=std::min(int(blocks.size()-1),pos/BLOCKSIZE);
				++blocki)
			blocks[blocki].recompute(begin(a)+blocki*BLOCKSIZE,
					begin(a)+std::min((int)a.size(),blocki*BLOCKSIZE+BLOCKSIZE+1));

		std::vector<int> maxsuf(blocks.size()+1);
		maxsuf.back()=INT_MIN;
		for(auto blocki=blocks.size();blocki--;)
			maxsuf[blocki]=std::max(maxsuf[blocki+1],blocks[blocki].max);

		int out=0;
		int minpre=INT_MAX;
		for(unsigned blocki=0;blocki<blocks.size();++blocki){
			out+=blocks[blocki].get(minpre,maxsuf[blocki+1]);
			minpre=std::min(minpre,blocks[blocki].min);
		}
		io::writeInt(out+1 /* nblock = nsplit+1 */);
		io::writeChar('\n');
	}
}


// Caching the results of the unchanged blocks.
// On my machine the previous hack test only take <4s to run.

#ifndef LOCAL
#define NDEBUG
#endif
#include<array>
#include<cassert>
#include<algorithm>
#include<climits>
#include<cstdio>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
namespace io{using namespace std;static const int buf_size=4096;static unsigned char buf[buf_size];static int buf_len=0,buf_pos=0;inline bool isEof(){if(buf_pos==buf_len){buf_pos=0,buf_len=fread(buf,1,buf_size,stdin);if(buf_pos==buf_len)return 1;}return 0;}inline int getChar(){return isEof()?-1:buf[buf_pos++];}inline int peekChar(){return isEof()?-1:buf[buf_pos];}inline bool seekEof(){int c;while((c=peekChar())!=-1&&c<=32)buf_pos++;return c==-1;}inline void skipBlanks(){while(!isEof()&&buf[buf_pos]<=32U)buf_pos++;}inline int readChar(){int c=getChar();while(c!=-1&&c<=32)c=getChar();return c;}inline int readUInt(){int c=readChar(),x=0;while('0'<=c&&c<='9')x=x*10+c-'0',c=getChar();return x;}template<class T=int>inline T readInt(){int s=1,c=readChar();T x=0;if(c=='-')s=-1,c=getChar();else if(c=='+')c=getChar();while('0'<=c&&c<='9')x=x*10+c-'0',c=getChar();return s==1?x:-x;}inline double readDouble(){int s=1,c=readChar();double x=0;if(c=='-')s=-1,c=getChar();while('0'<=c&&c<='9')x=x*10+c-'0',c=getChar();if(c=='.'){c=getChar();double coef=1;while('0'<=c&&c<='9')x+=(c-'0')*(coef*=1e-1),c=getChar();}return s==1?x:-x;}inline void readWord(char*s){int c=readChar();while(c>32)*s++=c,c=getChar();*s=0;}inline bool readLine(char*s){int c=getChar();while(c!='\n'&&c!=-1)*s++=c,c=getChar();*s=0;return c!=-1;}static int write_buf_pos=0;static char write_buf[buf_size];inline void writeChar(int x){if(write_buf_pos==buf_size)fwrite(write_buf,1,buf_size,stdout),write_buf_pos=0;write_buf[write_buf_pos++]=x;}inline void flush(){if(write_buf_pos){fwrite(write_buf,1,write_buf_pos,stdout),write_buf_pos=0;fflush(stdout);}}template<class T>inline void writeInt(T x,char end=0,int output_len=-1){if(x<0)writeChar('-'),x=-x;char s[24];int n=0;while(x||!n)s[n++]='0'+x%10,x/=10;while(n<output_len)s[n++]='0';while(n--)writeChar(s[n]);if(end)writeChar(end);}inline void writeWord(const char*s){while(*s)writeChar(*s++);}inline void writeDouble(double x,int output_len=0){if(x<0)writeChar('-'),x=-x;int t=(int)x;writeInt(t),x-=t;writeChar('.');for(int i=output_len-1;i>0;i--){x*=10;t=std::min(9,(int)x);writeChar('0'+t),x-=t;}x*=10;t=std::min(9,(int)(x+0.5));writeChar('0'+t);}static struct buffer_flusher_t{~buffer_flusher_t(){flush();}}buffer_flusher;};
#pragma GCC diagnostic pop

#include<vector>

int const BLOCKSIZE=1000;

struct block{
	struct interval{ // inclusive
		int l,r;
	};
	std::vector<interval> d;
	int min,max;

	template<class Iter>
	void recompute(Iter first,Iter last){
		assert(last-first<=BLOCKSIZE+1);
		assert(last-first>=2);

		std::array<int,BLOCKSIZE+1> minpre,maxsuf;
		d.reserve(last-first-1);
		d.clear();

		min=*first;
		for(int i=0;first+i!=last;++i)
			minpre[i]=min=std::min(min,first[i]);

		max=last[-1];
		for(auto i=last-first;i--;)
			maxsuf[i]=max=std::max(max,first[i]);

		for(auto i=last-first-1;i;--i){
			assert(minpre[i-1]!=maxsuf[i]);
			if(minpre[i-1]>maxsuf[i])
				d.push_back({maxsuf[i],minpre[i-1]});
		}

		assert(std::is_sorted(begin(d),end(d),[](interval x,interval y){
					return x.l<y.l;
					}));
	} // only O(n)

	int get(int minpre,int maxsuf)const{
		if(minpre<maxsuf)return 0;
		assert(minpre>maxsuf);
		auto const cond1=[](interval x,int y){return x.l<=y;};
		auto max_iter=cond1(d.back(),minpre) ? end(d) : std::lower_bound(begin(d),end(d),minpre,cond1);

		auto const cond2=[](interval x,int y){return x.r<y;};
		auto min_iter=cond2(d[0],maxsuf) ? begin(d) : std::lower_bound(begin(d),max_iter,maxsuf,cond2);

		return max_iter-min_iter;
		// number of segments that intersect [maxsuf..minpre]
	}
};

int main(){
	int n=io::readUInt();
	int nquery=io::readUInt();
	std::vector<int> a(n);
	std::generate(begin(a),end(a),io::readUInt);

	std::vector<block> blocks;
	for(int i=0;n-i*BLOCKSIZE>=2;++i){
		blocks.emplace_back();
		blocks[i].recompute(begin(a)+i*BLOCKSIZE,
				begin(a)+std::min((int)a.size(),i*BLOCKSIZE+BLOCKSIZE+1));
	}
	// NOTE one update may modify at most 2 block

	std::vector<int> maxsuf(blocks.size()+1);

	std::vector<int> minpre(blocks.size()+1); // exclusive

	auto const recompute_minmax=[&](){
		maxsuf.back()=INT_MIN;
		for(auto blocki=blocks.size();blocki--;)
			maxsuf[blocki]=std::max(maxsuf[blocki+1],blocks[blocki].max);

		minpre[0]=INT_MAX;
		for(auto blocki=1;blocki<=blocks.size();++blocki)
			minpre[blocki]=std::min(minpre[blocki-1],blocks[blocki-1].min);
	};
	recompute_minmax();

	int out=0;
	for(unsigned blocki=0;blocki<blocks.size();++blocki)
		out+=blocks[blocki].get(minpre[blocki],maxsuf[blocki+1]);

	while(nquery--){
		int pos=io::readUInt()-1;
		int x=io::readUInt();

		assert(x!=a[pos]);
		a[pos]=x;

		auto mincblock=pos==0 ? 0 : (pos-1)/BLOCKSIZE;
		auto maxcblock=std::min(int(blocks.size()-1),pos/BLOCKSIZE);

		auto const old_minpre=minpre;
		auto const old_maxsuf=maxsuf;

		recompute_minmax();

		for(int blocki=0;blocki<(int)blocks.size();++blocki)
			if(old_minpre[blocki]!=minpre[blocki] or old_maxsuf[blocki]!=maxsuf[blocki] or
					(mincblock<=blocki and blocki<=maxcblock))
				out-=blocks[blocki].get(old_minpre[blocki],old_maxsuf[blocki+1]);

		for(int blocki=mincblock;blocki<=maxcblock;++blocki)
			blocks[blocki].recompute(begin(a)+blocki*BLOCKSIZE,
					begin(a)+std::min((int)a.size(),blocki*BLOCKSIZE+BLOCKSIZE+1));

		for(int blocki=0;blocki<(int)blocks.size();++blocki)
			if(old_minpre[blocki]!=minpre[blocki] or old_maxsuf[blocki]!=maxsuf[blocki] or
					(mincblock<=blocki and blocki<=maxcblock))
				out+=blocks[blocki].get(minpre[blocki],maxsuf[blocki+1]);

		io::writeInt(out+1 /* nblock = nsplit+1 */);
		io::writeChar('\n');
	}
}


// I was hinted at the square root decomposition by the large time limit... (is that cheating?)
#ifndef LOCAL
#define NDEBUG
#endif
#include<cassert>
#include<algorithm>
#include<climits>
#include<cstdio>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
namespace io{using namespace std;static const int buf_size=4096;static unsigned char buf[buf_size];static int buf_len=0,buf_pos=0;inline bool isEof(){if(buf_pos==buf_len){buf_pos=0,buf_len=fread(buf,1,buf_size,stdin);if(buf_pos==buf_len)return 1;}return 0;}inline int getChar(){return isEof()?-1:buf[buf_pos++];}inline int peekChar(){return isEof()?-1:buf[buf_pos];}inline bool seekEof(){int c;while((c=peekChar())!=-1&&c<=32)buf_pos++;return c==-1;}inline void skipBlanks(){while(!isEof()&&buf[buf_pos]<=32U)buf_pos++;}inline int readChar(){int c=getChar();while(c!=-1&&c<=32)c=getChar();return c;}inline int readUInt(){int c=readChar(),x=0;while('0'<=c&&c<='9')x=x*10+c-'0',c=getChar();return x;}template<class T=int>inline T readInt(){int s=1,c=readChar();T x=0;if(c=='-')s=-1,c=getChar();else if(c=='+')c=getChar();while('0'<=c&&c<='9')x=x*10+c-'0',c=getChar();return s==1?x:-x;}inline double readDouble(){int s=1,c=readChar();double x=0;if(c=='-')s=-1,c=getChar();while('0'<=c&&c<='9')x=x*10+c-'0',c=getChar();if(c=='.'){c=getChar();double coef=1;while('0'<=c&&c<='9')x+=(c-'0')*(coef*=1e-1),c=getChar();}return s==1?x:-x;}inline void readWord(char*s){int c=readChar();while(c>32)*s++=c,c=getChar();*s=0;}inline bool readLine(char*s){int c=getChar();while(c!='\n'&&c!=-1)*s++=c,c=getChar();*s=0;return c!=-1;}static int write_buf_pos=0;static char write_buf[buf_size];inline void writeChar(int x){if(write_buf_pos==buf_size)fwrite(write_buf,1,buf_size,stdout),write_buf_pos=0;write_buf[write_buf_pos++]=x;}inline void flush(){if(write_buf_pos){fwrite(write_buf,1,write_buf_pos,stdout),write_buf_pos=0;fflush(stdout);}}template<class T>inline void writeInt(T x,char end=0,int output_len=-1){if(x<0)writeChar('-'),x=-x;char s[24];int n=0;while(x||!n)s[n++]='0'+x%10,x/=10;while(n<output_len)s[n++]='0';while(n--)writeChar(s[n]);if(end)writeChar(end);}inline void writeWord(const char*s){while(*s)writeChar(*s++);}inline void writeDouble(double x,int output_len=0){if(x<0)writeChar('-'),x=-x;int t=(int)x;writeInt(t),x-=t;writeChar('.');for(int i=output_len-1;i>0;i--){x*=10;t=std::min(9,(int)x);writeChar('0'+t),x-=t;}x*=10;t=std::min(9,(int)(x+0.5));writeChar('0'+t);}static struct buffer_flusher_t{~buffer_flusher_t(){flush();}}buffer_flusher;};
#pragma GCC diagnostic pop

#include<vector>

int const BLOCKSIZE=1000;

struct block{
	struct interval{ // inclusive
		int l,r;
	};
	std::vector<interval> d;
	int min,max;

	template<class Iter>
	void recompute(Iter first,Iter last){
		assert(last-first<=BLOCKSIZE+1);
		assert(last-first>=2);

		std::array<int,BLOCKSIZE+1> minpre,maxsuf;
		d.reserve(last-first-1);
		d.clear();

		min=*first;
		for(int i=0;first+i!=last;++i)
			minpre[i]=min=std::min(min,first[i]);

		max=last[-1];
		for(auto i=last-first;i--;)
			maxsuf[i]=max=std::max(max,first[i]);

		for(auto i=last-first-1;i;--i){
			assert(minpre[i-1]!=maxsuf[i]);
			if(minpre[i-1]>maxsuf[i])
				d.push_back({maxsuf[i],minpre[i-1]});
		}

		assert(std::is_sorted(begin(d),end(d),[](interval x,interval y){
					return x.l<y.l;
					}));
	} // only O(n)

	int get(int minpre,int maxsuf)const{
		if(minpre<maxsuf)return 0;
		assert(minpre>maxsuf);
		return int(
			std::lower_bound(begin(d),end(d),minpre,[](interval x,int y){return x.l<=y;})
			-
			std::lower_bound(begin(d),end(d),maxsuf,[](interval x,int y){return x.r<y;})
			);
		// number of segments that intersect [maxsuf..minpre]
	}
};

int main(){
	int n=io::readUInt();
	int nquery=io::readUInt();
	std::vector<int> a(n);
	std::generate(begin(a),end(a),io::readUInt);

	std::vector<block> blocks;
	for(int i=0;n-i*BLOCKSIZE>=2;++i){
		blocks.emplace_back();
		blocks[i].recompute(begin(a)+i*BLOCKSIZE,
				begin(a)+std::min((int)a.size(),i*BLOCKSIZE+BLOCKSIZE+1));
	}
	// NOTE one update may modify at most 2 block

	while(nquery--){
		int pos=io::readUInt()-1;
		int x=io::readUInt();

		assert(x!=a[pos]);
		a[pos]=x;

		for(int blocki=(pos==0 ? 0 : (pos-1)/BLOCKSIZE);blocki<=pos/BLOCKSIZE;++blocki)
			blocks[blocki].recompute(begin(a)+blocki*BLOCKSIZE,
					begin(a)+std::min((int)a.size(),blocki*BLOCKSIZE+BLOCKSIZE+1));

		std::vector<int> maxsuf(blocks.size()+1);
		maxsuf.back()=INT_MIN;
		for(auto blocki=blocks.size();blocki--;)
			maxsuf[blocki]=std::max(maxsuf[blocki+1],blocks[blocki].max);

		int out=0;
		int minpre=INT_MAX;
		for(unsigned blocki=0;blocki<blocks.size();++blocki){
			out+=blocks[blocki].get(minpre,maxsuf[blocki+1]);
			minpre=std::min(minpre,blocks[blocki].min);
		}
		io::writeInt(out+1 /* nblock = nsplit+1 */);
		io::writeChar('\n');
	}
}


// I was hinted at the square root decomposition by the large time limit... (is that cheating?)
#ifndef LOCAL
#define NDEBUG
#endif
#include<array>
#include<cassert>
#include<algorithm>
#include<climits>
#include<cstdio>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
namespace io{using namespace std;static const int buf_size=4096;static unsigned char buf[buf_size];static int buf_len=0,buf_pos=0;inline bool isEof(){if(buf_pos==buf_len){buf_pos=0,buf_len=fread(buf,1,buf_size,stdin);if(buf_pos==buf_len)return 1;}return 0;}inline int getChar(){return isEof()?-1:buf[buf_pos++];}inline int peekChar(){return isEof()?-1:buf[buf_pos];}inline bool seekEof(){int c;while((c=peekChar())!=-1&&c<=32)buf_pos++;return c==-1;}inline void skipBlanks(){while(!isEof()&&buf[buf_pos]<=32U)buf_pos++;}inline int readChar(){int c=getChar();while(c!=-1&&c<=32)c=getChar();return c;}inline int readUInt(){int c=readChar(),x=0;while('0'<=c&&c<='9')x=x*10+c-'0',c=getChar();return x;}template<class T=int>inline T readInt(){int s=1,c=readChar();T x=0;if(c=='-')s=-1,c=getChar();else if(c=='+')c=getChar();while('0'<=c&&c<='9')x=x*10+c-'0',c=getChar();return s==1?x:-x;}inline double readDouble(){int s=1,c=readChar();double x=0;if(c=='-')s=-1,c=getChar();while('0'<=c&&c<='9')x=x*10+c-'0',c=getChar();if(c=='.'){c=getChar();double coef=1;while('0'<=c&&c<='9')x+=(c-'0')*(coef*=1e-1),c=getChar();}return s==1?x:-x;}inline void readWord(char*s){int c=readChar();while(c>32)*s++=c,c=getChar();*s=0;}inline bool readLine(char*s){int c=getChar();while(c!='\n'&&c!=-1)*s++=c,c=getChar();*s=0;return c!=-1;}static int write_buf_pos=0;static char write_buf[buf_size];inline void writeChar(int x){if(write_buf_pos==buf_size)fwrite(write_buf,1,buf_size,stdout),write_buf_pos=0;write_buf[write_buf_pos++]=x;}inline void flush(){if(write_buf_pos){fwrite(write_buf,1,write_buf_pos,stdout),write_buf_pos=0;fflush(stdout);}}template<class T>inline void writeInt(T x,char end=0,int output_len=-1){if(x<0)writeChar('-'),x=-x;char s[24];int n=0;while(x||!n)s[n++]='0'+x%10,x/=10;while(n<output_len)s[n++]='0';while(n--)writeChar(s[n]);if(end)writeChar(end);}inline void writeWord(const char*s){while(*s)writeChar(*s++);}inline void writeDouble(double x,int output_len=0){if(x<0)writeChar('-'),x=-x;int t=(int)x;writeInt(t),x-=t;writeChar('.');for(int i=output_len-1;i>0;i--){x*=10;t=std::min(9,(int)x);writeChar('0'+t),x-=t;}x*=10;t=std::min(9,(int)(x+0.5));writeChar('0'+t);}static struct buffer_flusher_t{~buffer_flusher_t(){flush();}}buffer_flusher;};
#pragma GCC diagnostic pop

#include<vector>

int const BLOCKSIZE=1000;

struct block{
	struct interval{ // inclusive
		int l,r;
	};
	std::vector<interval> d;
	int min,max;

	template<class Iter>
	void recompute(Iter first,Iter last){
		assert(last-first<=BLOCKSIZE+1);
		assert(last-first>=2);

		std::array<int,BLOCKSIZE+1> minpre,maxsuf;
		d.reserve(last-first-1);
		d.clear();

		min=*first;
		for(int i=0;first+i!=last;++i)
			minpre[i]=min=std::min(min,first[i]);

		max=last[-1];
		for(auto i=last-first;i--;)
			maxsuf[i]=max=std::max(max,first[i]);

		for(auto i=last-first-1;i;--i){
			assert(minpre[i-1]!=maxsuf[i]);
			if(minpre[i-1]>maxsuf[i])
				d.push_back({maxsuf[i],minpre[i-1]});
		}

		assert(std::is_sorted(begin(d),end(d),[](interval x,interval y){
					return x.l<y.l;
					}));
	} // only O(n)

	int get(int minpre,int maxsuf)const{
		if(minpre<maxsuf)return 0;
		assert(minpre>maxsuf);
		return int(
			std::lower_bound(begin(d),end(d),minpre,[](interval x,int y){return x.l<=y;})
			-
			std::lower_bound(begin(d),end(d),maxsuf,[](interval x,int y){return x.r<y;})
			);
		// number of segments that intersect [maxsuf..minpre]
	}
};

int main(){
	int n=io::readUInt();
	int nquery=io::readUInt();
	std::vector<int> a(n);
	std::generate(begin(a),end(a),io::readUInt);

	std::vector<block> blocks;
	for(int i=0;n-i*BLOCKSIZE>=2;++i){
		blocks.emplace_back();
		blocks[i].recompute(begin(a)+i*BLOCKSIZE,
				begin(a)+std::min((int)a.size(),i*BLOCKSIZE+BLOCKSIZE+1));
	}
	// NOTE one update may modify at most 2 block

	while(nquery--){
		int pos=io::readUInt()-1;
		int x=io::readUInt();

		assert(x!=a[pos]);
		a[pos]=x;

		for(int blocki=(pos==0 ? 0 : (pos-1)/BLOCKSIZE);blocki<=pos/BLOCKSIZE;++blocki)
			blocks[blocki].recompute(begin(a)+blocki*BLOCKSIZE,
					begin(a)+std::min((int)a.size(),blocki*BLOCKSIZE+BLOCKSIZE+1));

		std::vector<int> maxsuf(blocks.size()+1);
		maxsuf.back()=INT_MIN;
		for(auto blocki=blocks.size();blocki--;)
			maxsuf[blocki]=std::max(maxsuf[blocki+1],blocks[blocki].max);

		int out=0;
		int minpre=INT_MAX;
		for(unsigned blocki=0;blocki<blocks.size();++blocki){
			out+=blocks[blocki].get(minpre,maxsuf[blocki+1]);
			minpre=std::min(minpre,blocks[blocki].min);
		}
		io::writeInt(out+1 /* nblock = nsplit+1 */);
		io::writeChar('\n');
	}
}


// Caching the results of the unchanged blocks.
// On my machine the previous hack test only take <4s to run.
//
// Also special-case some cases int get function so the time complexity is only O(1), not O(log n).
// I don't know if this is an optimization or deoptimization.
//
// ^ (more special case = more bug.)

#ifndef LOCAL
#define NDEBUG
#endif
#include<numeric>
#include<array>
#include<cassert>
#include<algorithm>
#include<climits>
#include<cstdio>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
namespace io{using namespace std;static const int buf_size=4096;static unsigned char buf[buf_size];static int buf_len=0,buf_pos=0;inline bool isEof(){if(buf_pos==buf_len){buf_pos=0,buf_len=fread(buf,1,buf_size,stdin);if(buf_pos==buf_len)return 1;}return 0;}inline int getChar(){return isEof()?-1:buf[buf_pos++];}inline int peekChar(){return isEof()?-1:buf[buf_pos];}inline bool seekEof(){int c;while((c=peekChar())!=-1&&c<=32)buf_pos++;return c==-1;}inline void skipBlanks(){while(!isEof()&&buf[buf_pos]<=32U)buf_pos++;}inline int readChar(){int c=getChar();while(c!=-1&&c<=32)c=getChar();return c;}inline int readUInt(){int c=readChar(),x=0;while('0'<=c&&c<='9')x=x*10+c-'0',c=getChar();return x;}template<class T=int>inline T readInt(){int s=1,c=readChar();T x=0;if(c=='-')s=-1,c=getChar();else if(c=='+')c=getChar();while('0'<=c&&c<='9')x=x*10+c-'0',c=getChar();return s==1?x:-x;}inline double readDouble(){int s=1,c=readChar();double x=0;if(c=='-')s=-1,c=getChar();while('0'<=c&&c<='9')x=x*10+c-'0',c=getChar();if(c=='.'){c=getChar();double coef=1;while('0'<=c&&c<='9')x+=(c-'0')*(coef*=1e-1),c=getChar();}return s==1?x:-x;}inline void readWord(char*s){int c=readChar();while(c>32)*s++=c,c=getChar();*s=0;}inline bool readLine(char*s){int c=getChar();while(c!='\n'&&c!=-1)*s++=c,c=getChar();*s=0;return c!=-1;}static int write_buf_pos=0;static char write_buf[buf_size];inline void writeChar(int x){if(write_buf_pos==buf_size)fwrite(write_buf,1,buf_size,stdout),write_buf_pos=0;write_buf[write_buf_pos++]=x;}inline void flush(){if(write_buf_pos){fwrite(write_buf,1,write_buf_pos,stdout),write_buf_pos=0;fflush(stdout);}}template<class T>inline void writeInt(T x,char end=0,int output_len=-1){if(x<0)writeChar('-'),x=-x;char s[24];int n=0;while(x||!n)s[n++]='0'+x%10,x/=10;while(n<output_len)s[n++]='0';while(n--)writeChar(s[n]);if(end)writeChar(end);}inline void writeWord(const char*s){while(*s)writeChar(*s++);}inline void writeDouble(double x,int output_len=0){if(x<0)writeChar('-'),x=-x;int t=(int)x;writeInt(t),x-=t;writeChar('.');for(int i=output_len-1;i>0;i--){x*=10;t=std::min(9,(int)x);writeChar('0'+t),x-=t;}x*=10;t=std::min(9,(int)(x+0.5));writeChar('0'+t);}static struct buffer_flusher_t{~buffer_flusher_t(){flush();}}buffer_flusher;};
#pragma GCC diagnostic pop

#include<vector>

int const BLOCKSIZE=1000;

struct block{
	struct interval{ // inclusive
		int l,r;
	};
	std::vector<interval> d;
	int min,max;

	template<class Iter>
	void recompute(Iter first,Iter last){
		assert(last-first<=BLOCKSIZE+1);
		assert(last-first>=2);

		std::array<int,BLOCKSIZE+1> minpre,maxsuf;
		d.reserve(last-first-1);
		d.clear();

		min=*first;
		for(int i=0;first+i!=last;++i)
			minpre[i]=min=std::min(min,first[i]);

		max=last[-1];
		for(auto i=last-first;i--;)
			maxsuf[i]=max=std::max(max,first[i]);

		for(auto i=last-first-1;i;--i){
			assert(minpre[i-1]!=maxsuf[i]);
			if(minpre[i-1]>maxsuf[i])
				d.push_back({maxsuf[i],minpre[i-1]});
		}

		assert(std::is_sorted(begin(d),end(d),[](interval x,interval y){
					return x.l<y.l;
					}));
	} // only O(n)

	int get(int minpre,int maxsuf)const{
		if(minpre<maxsuf or d.empty())return 0;
		assert(minpre>maxsuf);
		auto const cond1=[](interval x,int y){return x.l<=y;};
		auto max_iter=cond1(d.back(),minpre) ? end(d) : std::lower_bound(begin(d),end(d),minpre,cond1);

		auto const cond2=[](interval x,int y){return x.r<y;};
		auto min_iter=cond2(d[0],maxsuf) ? std::lower_bound(begin(d),max_iter,maxsuf,cond2) : begin(d);

		return max_iter-min_iter;
		// number of segments that intersect [maxsuf..minpre]
	}
};

int main(){
	int n=io::readUInt();
	int nquery=io::readUInt();
	std::vector<int> a(n);
	std::generate(begin(a),end(a),io::readUInt);

	std::vector<block> blocks;
	for(int i=0;n-i*BLOCKSIZE>=2;++i){
		blocks.emplace_back();
		blocks[i].recompute(begin(a)+i*BLOCKSIZE,
				begin(a)+std::min((int)a.size(),i*BLOCKSIZE+BLOCKSIZE+1));
	}
	// NOTE one update may modify at most 2 block

	std::vector<int> maxsuf(blocks.size()+1);

	std::vector<int> minpre(blocks.size()+1); // exclusive

	auto const recompute_minmax=[&](){
		maxsuf.back()=INT_MIN;
		for(auto blocki=blocks.size();blocki--;)
			maxsuf[blocki]=std::max(maxsuf[blocki+1],blocks[blocki].max);

		minpre[0]=INT_MAX;
		for(auto blocki=1;blocki<=blocks.size();++blocki)
			minpre[blocki]=std::min(minpre[blocki-1],blocks[blocki-1].min);
	};
	recompute_minmax();

	std::vector<int> getval(blocks.size());
	for(unsigned blocki=0;blocki<blocks.size();++blocki)
		getval[blocki]=blocks[blocki].get(minpre[blocki],maxsuf[blocki+1]);

	while(nquery--){
		int pos=io::readUInt()-1;
		int x=io::readUInt();

		assert(x!=a[pos]);
		a[pos]=x;

		auto mincblock=pos==0 ? 0 : (pos-1)/BLOCKSIZE;
		auto maxcblock=std::min(int(blocks.size()-1),pos/BLOCKSIZE);

		auto const old_minpre=minpre;
		auto const old_maxsuf=maxsuf;

		for(int blocki=mincblock;blocki<=maxcblock;++blocki)
			blocks[blocki].recompute(begin(a)+blocki*BLOCKSIZE,
					begin(a)+std::min((int)a.size(),blocki*BLOCKSIZE+BLOCKSIZE+1));

		recompute_minmax();

		for(int blocki=0;blocki<(int)blocks.size();++blocki)
			if(old_minpre[blocki]!=minpre[blocki] or old_maxsuf[blocki+1]!=maxsuf[blocki+1] or
					(mincblock<=blocki and blocki<=maxcblock))
				getval[blocki]=blocks[blocki].get(minpre[blocki],maxsuf[blocki+1]);

		io::writeInt(std::accumulate(begin(getval),end(getval),1));
		io::writeChar('\n');
	}
}


#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<iostream>
using namespace std;
#define ll long long
#define REP(a,b,c) for(int a=b;a<=c;a++)
#define re register
#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
typedef pair<int,int> pii;
#define mp make_pair
inline int gi()
{
	int f=1,sum=0;char ch=getchar();
	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
	return f*sum;
}
const int N=500010,Inf=1e6+1,M=Inf+20;
int tag[M<<2],mn[M<<2],cnt[M<<2],n,Q,a[N];
void pushup(int o)
{
	cnt[o]=0;
	mn[o]=min(mn[o<<1],mn[o<<1|1]);
	if(mn[o]==mn[o<<1])cnt[o]+=cnt[o<<1];
	if(mn[o]==mn[o<<1|1])cnt[o]+=cnt[o<<1|1];
}
void puttag(int o,int v){mn[o]+=v;tag[o]+=v;}
void pushdown(int o)
{
	if(tag[o])
	{
		puttag(o<<1,tag[o]);puttag(o<<1|1,tag[o]);
		tag[o]=0;
	}
}
void modify(int o,int l,int r,int posl,int posr,int v)
{
	if(posl<=l&&r<=posr){puttag(o,v);return;}
	int mid=(l+r)>>1;pushdown(o);
	if(posl<=mid)modify(o<<1,l,mid,posl,posr,v);
	if(mid<posr)modify(o<<1|1,mid+1,r,posl,posr,v);
	pushup(o);
}
void modify(int o,int l,int r,int pos,int v)
{
	if(l==r){cnt[o]+=v;return;}
	int mid=(l+r)>>1;pushdown(o);
	if(pos<=mid)modify(o<<1,l,mid,pos,v);
	else modify(o<<1|1,mid+1,r,pos,v);
	pushup(o);
}
int query(int o,int l,int r,int posl,int posr)
{
	if(posl<=l&&r<=posr)return mn[o]==1?cnt[o]:0;
	int mid=(l+r)>>1,ret=0;pushdown(o);
	if(posl<=mid)ret=query(o<<1,l,mid,posl,posr);
	if(mid<posr)ret+=query(o<<1|1,mid+1,r,posl,posr);
	pushup(o);return ret;
}
void modify(int l,int r,int v)
{
	if(l==r)return;if(l>r)swap(l,r);
	modify(1,0,Inf,l,r-1,v);
}
int main()
{
	n=gi();Q=gi();
	for(int i=1;i<=n;i++)a[i]=gi();
	a[0]=Inf;a[n+1]=0;
	for(int i=0;i<=n;i++)modify(a[i],a[i+1],1),modify(1,0,Inf,a[i],1);
	while(Q--)
	{
		int p=gi(),v=gi();
		modify(a[p-1],a[p],-1);modify(a[p],a[p+1],-1);modify(1,0,Inf,a[p],-1);
		a[p]=v;
		modify(a[p-1],a[p],1);modify(a[p],a[p+1],1);modify(1,0,Inf,a[p],1);
		printf("%d\n",query(1,0,Inf,1,Inf-1));
	}
	return 0;
}


#include<bits/stdc++.h>
template<class T> inline void read(T &x){
  x=0; register char c=getchar(); register bool f=0;
  while(!isdigit(c))f^=c=='-',c=getchar();
  while(isdigit(c))x=x*10+c-'0',c=getchar(); if(f)x=-x;
}
const int N=1e6+10;
int n,m,ans,a[N],tmp[N];
struct Query{
  int k,v;
}q[N];
struct Segment{
  int l,r,mid,min,cnt,tag;
}p[N<<2];
inline void pushup(int u,int x){p[u].min+=x,p[u].tag+=x;}
inline void pushdown(int u){if(p[u].tag)pushup(u<<1,p[u].tag),pushup(u<<1|1,p[u].tag),p[u].tag=0;}
inline void maintain(int u){
  p[u].min=std::min(p[u<<1].min,p[u<<1|1].min);
  p[u].cnt=(p[u].min==p[u<<1].min?p[u<<1].cnt:0)+(p[u].min==p[u<<1|1].min?p[u<<1|1].cnt:0);
}
void build(int u,int l,int r){
  p[u].l=l,p[u].r=r,p[u].mid=(l+r)>>1;
  if(l==r)return;
  build(u<<1,l,p[u].mid);
  build(u<<1|1,p[u].mid+1,r);
}
void affect(int u,int k,int x){
  if(p[u].l==p[u].r)return p[u].cnt+=x,void(0);
  pushdown(u);
  affect(k<=p[u].mid?u<<1:u<<1|1,k,x);
  maintain(u);
}
void modify(int u,int l,int r,int x){
  if(p[u].l==l&&p[u].r==r)return pushup(u,x);
  pushdown(u);
  if(r<=p[u].mid)modify(u<<1,l,r,x);
  else if(l>p[u].mid)modify(u<<1|1,l,r,x);
  else modify(u<<1,l,p[u].mid,x),modify(u<<1|1,p[u].mid+1,r,x);
  maintain(u);
}
void active(int k,int x){
  if(a[k]<a[k+1]){
    modify(1,a[k]+1,a[k+1],x);
  }else{
    modify(1,a[k+1]+1,a[k],x);
  }
}
int main(){
#ifdef memset0
  freopen("1.in","r",stdin);
#endif
  read(n),read(m);
  for(int i=1;i<=n;i++)read(a[i]);
  for(int i=1;i<=m;i++)read(q[i].k),read(q[i].v);
  a[0]=1919810,a[n+1]=-114514;
  for(int i=0;i<=n+1;i++)tmp[++*tmp]=a[i];
  for(int i=1;i<=m;i++)tmp[++*tmp]=q[i].v;
  std::sort(tmp+1,tmp+*tmp+1);
  *tmp=std::unique(tmp+1,tmp+*tmp+1)-tmp-1;
  for(int i=0;i<=n+1;i++)a[i]=std::lower_bound(tmp+1,tmp+*tmp+1,a[i])-tmp;
  for(int i=1;i<=m;i++)q[i].v=std::lower_bound(tmp+1,tmp+*tmp+1,q[i].v)-tmp;
  build(1,2,*tmp);
  for(int i=0;i<=n;i++)active(i,1);
  for(int i=1;i<=n;i++)affect(1,a[i],1);
  for(int i=1;i<=m;i++){
    active(q[i].k-1,-1),active(q[i].k,-1),affect(1,a[q[i].k],-1);
    a[q[i].k]=q[i].v;
    active(q[i].k-1,1),active(q[i].k,1),affect(1,a[q[i].k],1);
    printf("%d\n",p[1].min==1?p[1].cnt:0);
  }
}


#include<bits/stdc++.h>
template<class T> inline void read(T &x){
  x=0; register char c=getchar(); register bool f=0;
  while(!isdigit(c))f^=c=='-',c=getchar();
  while(isdigit(c))x=x*10+c-'0',c=getchar(); if(f)x=-x;
}
const int N=5e5+10;
int n,m,ans,a[N],tmp[N];
struct Query{
  int k,v;
}q[N];
struct Segment{
  int l,r,mid,min,cnt,tag;
}p[N<<2];
inline void pushup(int u,int x){p[u].min+=x,p[u].tag+=x;}
inline void pushdown(int u){if(p[u].tag)pushup(u<<1,p[u].tag),pushup(u<<1|1,p[u].tag),p[u].tag=0;}
inline void maintain(int u){
  p[u].min=std::min(p[u<<1].min,p[u<<1|1].min);
  p[u].cnt=(p[u].min==p[u<<1].min?p[u<<1].cnt:0)+(p[u].min==p[u<<1|1].min?p[u<<1|1].cnt:0);
}
void build(int u,int l,int r){
  p[u].l=l,p[u].r=r,p[u].mid=(l+r)>>1;
  if(l==r)return;
  build(u<<1,l,p[u].mid);
  build(u<<1|1,p[u].mid+1,r);
}
void affect(int u,int k,int x){
  if(p[u].l==p[u].r)return p[u].cnt+=x,void(0);
  pushdown(u);
  affect(k<=p[u].mid?u<<1:u<<1|1,k,x);
  maintain(u);
}
void modify(int u,int l,int r,int x){
  if(p[u].l==l&&p[u].r==r)return pushup(u,x);
  pushdown(u);
  if(r<=p[u].mid)modify(u<<1,l,r,x);
  else if(l>p[u].mid)modify(u<<1|1,l,r,x);
  else modify(u<<1,l,p[u].mid,x),modify(u<<1|1,p[u].mid+1,r,x);
  maintain(u);
}
void active(int k,int x){
  if(a[k]<a[k+1]){
    modify(1,a[k]+1,a[k+1],x);
  }else{
    modify(1,a[k+1]+1,a[k],x);
  }
}
int main(){
#ifdef memset0
  freopen("1.in","r",stdin);
#endif
  read(n),read(m);
  for(int i=1;i<=n;i++)read(a[i]);
  for(int i=1;i<=m;i++)read(q[i].k),read(q[i].v);
  a[0]=1919810,a[n+1]=-114514;
  for(int i=0;i<=n+1;i++)tmp[++*tmp]=a[i];
  for(int i=1;i<=m;i++)tmp[++*tmp]=q[i].v;
  std::sort(tmp+1,tmp+*tmp+1);
  *tmp=std::unique(tmp+1,tmp+*tmp+1)-tmp-1;
  for(int i=0;i<=n+1;i++)a[i]=std::lower_bound(tmp+1,tmp+*tmp+1,a[i])-tmp;
  for(int i=1;i<=m;i++)q[i].v=std::lower_bound(tmp+1,tmp+*tmp+1,q[i].v)-tmp;
  build(1,2,*tmp);
  for(int i=0;i<=n;i++)active(i,1);
  for(int i=1;i<=n;i++)affect(1,a[i],1);
  for(int i=1;i<=m;i++){
    active(q[i].k-1,-1),active(q[i].k,-1),affect(1,a[q[i].k],-1);
    a[q[i].k]=q[i].v;
    active(q[i].k-1,1),active(q[i].k,1),affect(1,a[q[i].k],1);
    printf("%d\n",p[1].min==1?p[1].cnt:0);
  }
}


// So when you feel like hope is gone, Look inside you and be strong, And you'll finally see the truth, That a hero lies in you ...

#include<bits/stdc++.h>

#define F first
#define S second
#define PB push_back
#define sz(s) int((s).size())
#define bit(n,k) (((n)>>(k))&1)

using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

const int maxn = 5e5 + 10, SQ1= 1500, SQ2 = (maxn / SQ1) + 3, inf = 1e8;

template<typename A, typename B> ostream& operator << (ostream& out, pair<A, B> p){
    out << "{ " << p.F << ", " << p.S <<" }";
    return out;
}
template<typename T> ostream& operator << (ostream& out, vector<T> v){
    out << "[ ";
    for(int i = 0; i < sz(v); i++){
	out << v[i];
	if(i != sz(v)-1)
	    out << " ,";
    }
    out << " ]";
    return out;
}

int a[SQ2][SQ1+10], mn[SQ2][SQ1 + 10], mx[SQ2][SQ1 + 10], MN[SQ2 + 10], MX[SQ2 + 10];
vector<int> mnv[SQ2], mxv[SQ2];
int BMN[SQ2], BMX[SQ2], RMN[SQ2], LMX[SQ2];

void build(int i){
    BMN[i] = BMX[i] = inf + 1000;

    mn[i][0] = a[i][0];
    for(int j = 1; j < SQ1; j++)
	mn[i][j] = min(mn[i][j-1], a[i][j]);
    mx[i][SQ1] = -inf;
    for(int j = SQ1-1; j >= 0; j--)
	mx[i][j] = max(mx[i][j+1], a[i][j]);
    mnv[i].clear();
    mxv[i].clear();
    for(int j = 0; j < SQ1; j++){
	if(mn[i][j] >= mx[i][j+1])
	    mnv[i].PB(mn[i][j]), mxv[i].PB(mx[i][j+1]);
    }
    reverse(mnv[i].begin(), mnv[i].end());
    reverse(mxv[i].begin(), mxv[i].end());
}

int main(){
    ios_base::sync_with_stdio(false); cin.tie(0); cout.tie();

    int n,q;
    cin >> n >> q;

    for(int i = 0; i < SQ2; i++)
	for(int j = 0; j < SQ1+10; j++)
	    a[i][j] = -inf;
    for(int i = 0; i < n; i++){
	cin >> a[i/SQ1][i%SQ1];
    }
    int N = (n-1)/SQ1;
    for(int i = 0; i <= N; i++){
	build(i);
    }
    while(q--){
	int pos, x;
	cin >> pos >> x;
	--pos;
	a[pos/SQ1][pos%SQ1] = x;
	build(pos/SQ1);
	int ans = 0;
	for(int i = 0; i <= N; i++)
	    MN[i] = min( (i == 0 ? inf : MN[i-1]), mn[i][SQ1-1] );
	MX[N+1] = -inf +1;
	for(int i = N; i >= 0; i--)
	    MX[i] = max( MX[i+1], mx[i][0] );
	int _MN = inf, _MX = MX[1];
	for(int i = 0; i <= N; i++){
	    if(_MN >= _MX){
		if(_MN != BMN[i])
		    RMN[i] = upper_bound(mxv[i].begin(), mxv[i].end(), _MN) - mxv[i].begin();
		if(_MX != BMX[i])
		    LMX[i] = lower_bound(mnv[i].begin(), mnv[i].end(), _MX) - mnv[i].begin();// kamtar az in hazf
		BMN[i] = _MN, BMX[i] = _MX;
		ans+= max(int(0), RMN[i]-LMX[i]);
	    }
	    _MN = MN[i], _MX = MX[i+2];
	}
	cout << ans << "\n";
    }
    return 0;
}
// #pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")


# include <bits/stdc++.h>
//https://codeforces.com/contest/1270/problem/H
// I give up on debugging this ):
using namespace std;
typedef pair<int, int> pii;
typedef vector<int> vi;
int n, q;
vi a;

typedef pii T;
static constexpr T unit = pii(INT_MAX, INT_MIN);

struct Tree {
    static T f(T aval, T b) { return pii(min(aval.first, b.first), max(aval.second, b.second)); }

    vector<T> s;
    int n;

    Tree(int n = 0, T def = unit) : s(static_cast<unsigned int>(2 * n), def), n(n) {}

    void update(int pos, T val) {
        for (s[pos += n] = val; pos /= 2;)
            s[pos] = f(s[pos * 2], s[pos * 2 + 1]);
    }

    T query(int b, int e) { // query [b, e)
        T ra = unit, rb = unit;
        for (b += n, e += n; b < e; b /= 2, e /= 2) {
            if (b % 2) ra = f(ra, s[b++]);
            if (e % 2) rb = f(s[--e], rb);
        }
        return f(ra, rb);
    }
} tree;

struct Component {
    int l, r, minV, maxV;

    bool operator<(Component o) const {
        // still a total ordering, but now we can search tree sets based on multiple keys
        if ((r == -1 || o.r == -1) && (minV != o.minV)) {
            return minV > o.minV;
        } else if ((r == -2 || o.r == -2) && (maxV != o.maxV)) {
            return maxV > o.maxV;
        } else if (l != o.l) {
            return l < o.l;
        } else {
            return r < o.r;
        }
    }
};

set<Component> comps;

void check() {
    for (Component c:comps) {
        assert(c.l < c.r);
        assert(c.minV <= c.maxV);
        cout << c.l << " " << c.r << " " << c.minV << " " << c.maxV << " ";
    }
    for (auto it = comps.begin(); it != comps.end();) {
        Component x = *it++;
        if (it == comps.end()) {
            break;
        }
        Component y = *it;
        assert(x.r == y.l);
        assert(x.minV >= y.maxV);
    }
}

void insertMerged(Component l, Component r){
    if(l.l == l.r){
        comps.insert(r);
    }else if(r.l == r.r){
        comps.insert(l);
    }else if(l.minV >= r.maxV){
        comps.insert(l);
        comps.insert(r);
    }else{
        comps.insert({l.l, r.r, min(l.minV, r.minV), max(l.maxV, r.maxV)});
    }
}

int update(int ind, int val) {
    a[ind] = val;
    tree.update(ind, pii(val, val));
    // see if we destroy the component a belongs to
    auto oldComp = comps.upper_bound({ind, n, 0, 0});
    if (oldComp != comps.begin()) {
        oldComp--;
    }
    int rBound = oldComp->r, lBound = oldComp->l;
    pii before = tree.query(oldComp->l, ind);
    pii after = tree.query(ind + 1, oldComp->r);
    if (before.first < val && val < after.second) {
        return comps.size();
    }
    // no connection to the right side
    if (val >= tree.query(ind + 1, n).second
         // also, a left merge will go all the way to the left
         && (before == unit || before.first < val)) {
        // merge left side
        Component leftComp = {lBound, ind + 1, min(val, before.first), max(val, before.second)};
        auto mergeComp = comps.upper_bound({lBound, -1, val, 0});
        if (mergeComp != comps.end() && val > mergeComp->minV && ind >= mergeComp->r) {
            leftComp.l = mergeComp->l;
            while (oldComp != mergeComp) {
                leftComp.maxV = max(leftComp.maxV, mergeComp->maxV);
                leftComp.minV = min(leftComp.minV, mergeComp->minV);
                mergeComp = comps.erase(mergeComp);
            }
        }
        comps.erase(oldComp);
        Component rComp = {ind + 1, rBound, after.first, after.second};
        insertMerged(leftComp, rComp);
    } else {
        Component rightComp = {ind, rBound, min(val, after.first), max(val, after.second)};
        auto mergeComp = comps.lower_bound({ind, -2, 0, val});
        if ((mergeComp == comps.end()) ||
            (mergeComp != comps.begin() && mergeComp != oldComp && val >= mergeComp->minV)) {
            mergeComp--;
        }
        if (val < mergeComp->maxV && ind < mergeComp->l) {
            rightComp.r = mergeComp->r;
            while (oldComp != mergeComp) {
                oldComp = comps.erase(oldComp);
                rightComp.minV = min(rightComp.minV, oldComp->minV);
                rightComp.maxV = max(rightComp.maxV, oldComp->maxV);
            }
        }
        comps.erase(oldComp);
        Component lComp = {lBound, ind, before.first, before.second};
        insertMerged(lComp, rightComp);
    }
    return comps.size();
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> q;
    bool bad = false;
    tree = Tree(n, pii(0, 0));
    a = vi(n, 0);
    comps.insert({0, n, 0, 0});
    for (int i = 0; i < n; i++) {
        cin >> a[i];
        update(i, a[i]);
    }
    if(a[0] == 1000000){
        bad = true;
    }
    for (int i = 0; i < q; i++) {
        int pos, val;
        cin >> pos >> val;
        if(bad && i==360941){
            check();
            cout << pos - 1 << " " << val;
            update(pos - 1, val);
            check();
        }
        cout << update(pos - 1, val) << endl;
    }
    flush(cout);
    return 0;
}


# include <bits/stdc++.h>
//https://codeforces.com/contest/1270/problem/H
using namespace std;
typedef vector<int> vi;
int n, q;
vi arr;
int maxV = 1000001;

// f[i]: the number of values 1<=j<n  arr such that (arr[j]>=i-n) != (arr[j-1]>=i-n) if i > n, else min(f[2*i], f[2*i+1])
// count[i]: the number of values left<=j<right  arr such that f[i] == f[i-n] if i > n, else the number of times i-n appears in a.
struct SegTree {
    SegTree *l, *r;
    int lo, mid, hi, fLazy = 0, f = 0, count = 0;

    SegTree(int lo, int hi) : lo(lo), hi(hi) {
        mid = lo + (hi - lo) / 2;
        if (lo + 1 < hi) {
            l = new SegTree(lo, mid);
            r = new SegTree(mid, hi);
            merge();
        }
    }

    void merge() {
        f = min(l->f, r->f);
        count = 0;
        if (f == r->f) {
            count += r->count;
        }
        if (f == l->f) {
            count += l->count;
        }
    }

    void push() {
        if (fLazy) {
            l->addF(lo, hi, fLazy), r->addF(lo, hi, fLazy), fLazy = 0;
        }
    }

    int query(int L, int R) {
        if (R <= lo || hi <= L) { return 0; }
        if (lo + 1 != hi) { push(); }
        if (L <= lo && hi <= R) { return f == 1 ? count : 0; }
        int ans = l->query(L, R) + r->query(L, R);
        merge();
        return ans;
    }

    void updCount(int ind, int diff) {
        if (ind == lo && hi == ind + 1) {
            count+= diff;
        } else {
            push();
            if (ind < mid) {
                l->updCount(ind, diff);
            } else {
                assert(ind < hi);
                r->updCount(ind, diff);
            }
            merge();
        }
    }

    void addF(int L, int R, int x) {
        if (R <= lo || hi <= L) return;
        if (L <= lo && hi <= R) {
            f += x;
            if (lo + 1 != hi) {
                fLazy += x;
            }
        } else {
            push(), l->addF(L, R, x), r->addF(L, R, x), merge();
        }
    }

    void upd(int a, int b, int delta) {
        addF(min(a, b), max(a, b), delta);
    }

    void addToTree(int pos, int add) {
        upd(arr[pos - 1], arr[pos], add);
        upd(arr[pos], arr[pos + 1], add);
        updCount(arr[pos], add);
    }

};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> q;
    arr = vi(n + 2, 0);
    for (int i = 1; i <= n; i++) {
        cin >> arr[i];
    }
    arr[0] = maxV;
    arr[n + 1] = 0;
    SegTree tree = SegTree(0, maxV);
    for (int i = 1; i <= n; i++) {
        tree.updCount(arr[i], 1);
    }
    for (int i = 0; i <= n; i++) {
        tree.upd(arr[i], arr[i + 1], 1);
    }
    for (int i = 0; i < q; i++) {
        int pos, val;
        cin >> pos >> val;
        tree.addToTree(pos, -1);
        arr[pos] = val;
        tree.addToTree(pos, 1);
        cout << tree.query(0, maxV) << endl;
    }
    flush(cout);
    return 0;
}


# include <bits/stdc++.h>
//https://codeforces.com/contest/1270/problem/H
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
int n, q;
vi a;

typedef pii T;
static constexpr T unit = pii(INT_MAX, INT_MIN);

struct Tree {
    T f(T a, T b) { return pii(min(a.first, b.first), max(a.second, b.second)); }

    vector<T> s;
    int n;

    Tree(int n = 0, T def = unit) : s(static_cast<unsigned int>(2 * n), def), n(n) {}

    void update(int pos, T val) {
        for (s[pos += n] = val; pos /= 2;)
            s[pos] = f(s[pos * 2], s[pos * 2 + 1]);
    }

    T query(int b, int e) { // query [b, e)
        T ra = unit, rb = unit;
        for (b += n, e += n; b < e; b /= 2, e /= 2) {
            if (b % 2) ra = f(ra, s[b++]);
            if (e % 2) rb = f(s[--e], rb);
        }
        return f(ra, rb);
    }
} tree;

struct Component {
    int l, r, minV, maxV;

    bool operator<(Component o) const {
        // still a total ordering, but now we can search tree sets based on multiple keys
        if ((r == -1 || o.r == -1) && (minV != o.minV)) {
            return minV > o.minV;
        } else if ((r == -2 || o.r == -2) && (maxV != o.maxV)) {
            return maxV > o.maxV;
        } else if (l != o.l) {
            return l < o.l;
        } else {
            return r < o.r;
        }
    }
};

set<Component> comps;

void check() {
    for (Component c:comps) {
        assert(c.l < c.r);
        assert(c.minV <= c.maxV);
    }
    for (auto it = comps.begin(); it != comps.end();) {
        Component x = *it++;
        if (it == comps.end()) {
            break;
        }
        Component y = *it;
        assert(x.r == y.l);
        assert(x.minV >= y.maxV);
    }
}

int update(int ind, int val) {
    a[ind] = val;
    tree.update(ind, pii(val, val));
    // see if we destroy the component a belongs to
    auto oldComp = comps.upper_bound({ind, n, 0, 0});
    if (oldComp != comps.begin()) {
        oldComp--;
    }
    int rBound = oldComp->r, lBound = oldComp->l;
    pii before = tree.query(oldComp->l, ind);
    pii after = tree.query(ind + 1, oldComp->r);
    if (before.first < val && val < after.second) {
        return comps.size();
    }
    int res = tree.query(ind + 1, n).second;
    // no connection to the right side, merge left side
    if (val >= (after == unit ? INT_MAX : after.second) ||
        ((after == unit && (ind + 1 == n || val >= res))
        // also, a left merge will go all the way to the left
        && (before == unit ? INT_MIN : before.first) < val)) {
        Component leftComp = {lBound, ind + 1, min(val, before.first), max(val, before.second)};
        auto mergeComp = comps.upper_bound({lBound, -1, val, 0});
        if (mergeComp != comps.end() && val > mergeComp->minV && ind >= mergeComp->r) {
            leftComp.l = mergeComp->l;
            while (oldComp != mergeComp) {
                leftComp.maxV = max(leftComp.maxV, mergeComp->maxV);
                leftComp.minV = min(leftComp.minV, mergeComp->minV);
                mergeComp = comps.erase(mergeComp);
            }
        }
        oldComp = comps.erase(oldComp);
        if (rBound != ind + 1) {
            if (leftComp.minV >= after.second) {
                comps.insert({ind + 1, rBound, after.first, after.second});
                comps.insert(leftComp);
            } else {
                comps.insert({leftComp.l, rBound, min(leftComp.minV, after.first), max(leftComp.maxV, after.second)});
            }
        } else {
            comps.insert(leftComp);
        }
    } else {
        Component rightComp = {ind, rBound, min(val, after.first), max(val, after.second)};
        auto mergeComp = comps.lower_bound({lBound, -2, 0, val});
        if (mergeComp != comps.begin() && mergeComp != oldComp && val >= mergeComp->minV) {
            mergeComp--;
        }
        if (mergeComp != comps.end() && val < mergeComp->maxV && ind < mergeComp->l) {
            rightComp.r = mergeComp->r;
            while (oldComp != mergeComp) {
                rightComp.minV = min(rightComp.minV, oldComp->minV);
                rightComp.maxV = max(rightComp.maxV, oldComp->maxV);
                oldComp = comps.erase(oldComp);
            }
        }
        oldComp = comps.erase(oldComp);
        if (lBound != ind) {
            if (before.first >= rightComp.maxV) {
                comps.insert(rightComp);
                comps.insert({lBound, ind, before.first, before.second});
            } else {
                comps.insert({lBound, rightComp.r, min(before.first, rightComp.minV),
                              max(before.second, rightComp.maxV)});
            }
        } else {
            comps.insert(rightComp);
        }
    }
    return comps.size();
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> q;
    tree = Tree(n, pii(0, 0));
    a = vi(n, 0);
    comps.insert({0, n, 0, 0});
    for (int i = 0; i < n; i++) {
        cin >> a[i];
        update(i, a[i]);
    }
    for (int i = 0; i < q; i++) {
        int pos, val;
        cin >> pos >> val;
        cout << update(pos - 1, val) << endl;
    }
    flush(cout);
    return 0;
}


# include <bits/stdc++.h>
//https://codeforces.com/contest/1270/problem/H
using namespace std;
typedef vector<int> vi;
int n, q;
vi arr;

// f[i]: the number of values 1<=j<n  arr such that (arr[j]>=i-n) != (arr[j-1]>=i-n) if i > n, else min(f[2*i], f[2*i+1])
// count[i]: the number of values left<=j<right  arr such that f[i] == f[i-n] if i > n, else the number of times i-n appears in a.
struct SegTree {
    SegTree *l, *r;
    int lo, mid, hi, fLazy = 0, f = 0, count = 0;

    SegTree(int lo, int hi) : lo(lo), hi(hi) {
        mid = lo + (hi - lo) / 2;
        if (lo + 1 < hi) {
            l = new SegTree(lo, mid);
            r = new SegTree(mid, hi);
            merge();
        }
    }

    void merge() {
        assert(l->fLazy + r->fLazy == 0);
        f = min(l->f, r->f);
        count = 0;
        if (f == r->f) {
            count += r->count;
        }
        if (f == l->f) {
            count += l->count;
        }
    }

    void push() {
        assert(l + 1 != r);
        if (fLazy) {
            l->addF(lo, hi, fLazy), r->addF(lo, hi, fLazy), fLazy = 0;
        }
    }

    int query(int L, int R) {
        if (R <= lo || hi <= L) { return 0; }
        if (lo + 1 != hi) { push(); }
        if (L <= lo && hi <= R) { return f == 1 ? count : 0; }
        int ans = l->query(L, R) + r->query(L, R);
        merge();
        return ans;
    }

    void updCount(int ind, int diff) {
        if (ind == lo && hi == ind + 1) {
            count+= diff;
        } else {
            push();
            if (ind < mid) {
                l->updCount(ind, diff);
            } else {
                assert(ind < hi);
                r->updCount(ind, diff);
            }
            merge();
        }
    }

    void addF(int L, int R, int x) {
        if (R <= lo || hi <= L) return;
        if (L <= lo && hi <= R) {
            f += x;
            if (lo + 1 != hi) {
                fLazy += x;
                push();
            }
        } else {
            push(), l->addF(L, R, x), r->addF(L, R, x), merge();
        }
    }

    void upd(int a, int b, int delta) {
        addF(min(a, b), max(a, b), delta);
    }

    void addToTree(int pos, int add) {
        upd(arr[pos - 1], arr[pos], add);
        upd(arr[pos], arr[pos + 1], add);
        updCount(arr[pos], add);
    }

};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> q;
    arr = vi(n + 2, 0);
    int maxV = 0;
    for (int i = 1; i <= n; i++) {
        cin >> arr[i];
        maxV = max(arr[i], maxV);
    }
    arr[0] = ++maxV;
    arr[n + 1] = 0;
    SegTree tree = SegTree(0, maxV);
    for (int i = 1; i <= n; i++) {
        tree.updCount(arr[i], 1);
    }
    for (int i = 0; i <= n; i++) {
        tree.upd(arr[i], arr[i + 1], 1);
    }
    for (int i = 0; i < q; i++) {
        int pos, val;
        cin >> pos >> val;
        tree.addToTree(pos, -1);
        arr[pos] = val;
        tree.addToTree(pos, 1);
        cout << tree.query(0, maxV) << "\n";
    }
    flush(cout);
    return 0;
}


# include <bits/stdc++.h>
//https://codeforces.com/contest/1270/problem/H
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
int n, q;
vi a;

typedef pii T;
static constexpr T unit = pii(INT_MAX, INT_MIN);

struct Tree {
    T f(T a, T b) { return pii(min(a.first, b.first), max(a.second, b.second)); }

    vector<T> s;
    int n;

    Tree(int n = 0, T def = unit) : s(static_cast<unsigned int>(2 * n), def), n(n) {}

    void update(int pos, T val) {
        for (s[pos += n] = val; pos /= 2;)
            s[pos] = f(s[pos * 2], s[pos * 2 + 1]);
    }

    T query(int b, int e) { // query [b, e)
        T ra = unit, rb = unit;
        for (b += n, e += n; b < e; b /= 2, e /= 2) {
            if (b % 2) ra = f(ra, s[b++]);
            if (e % 2) rb = f(s[--e], rb);
        }
        return f(ra, rb);
    }
} tree;

struct Component {
    int l, r, minV, maxV;

    bool operator<(Component o) const {
        // still a total ordering, but now we can search tree sets based on multiple keys
        if ((r == -1 || o.r == -1) && (minV != o.minV)) {
            return minV > o.minV;
        } else if ((r == -2 || o.r == -2) && (maxV != o.maxV)) {
            return maxV > o.maxV;
        } else if (l != o.l) {
            return l < o.l;
        } else {
            return r < o.r;
        }
    }
};

set<Component> comps;

void check() {
    for (Component c:comps) {
        assert(c.l < c.r);
        assert(c.minV <= c.maxV);
    }
    for (auto it = comps.begin(); it != comps.end();) {
        Component x = *it;
        Component y = *++it;
        if (it == comps.end()) {
            break;
        }
        assert(x.r == y.l);
        assert(x.minV >= y.maxV);
    }
}

int update(int ind, int val) {
    a[ind] = val;
    tree.update(ind, pii(val, val));
    // see if we destroy the component a belongs to
    auto oldComp = comps.upper_bound({ind, n, 0, 0});
    if (oldComp != comps.begin()) {
        oldComp--;
    }
    int rBound = oldComp->r, lBound = oldComp->l;
    pii before = tree.query(oldComp->l, ind);
    pii after = tree.query(ind + 1, oldComp->r);
    if(before.first < val && val < after.second){
        return comps.size();
    }
    // no connection to the right side, merge left side
    if (val >= (after.second == INT_MIN ? INT_MAX : after.second) ||
        (after == unit && (ind + 1 == n || val >= tree.query(ind + 1, n).second))) {
        Component leftComp = {lBound, ind + 1, min(val, before.first), max(val, before.second)};
        auto mergeComp = comps.upper_bound({lBound, -1, val, 0});
        if (mergeComp != comps.end() && val > mergeComp->minV && ind >= mergeComp->r) {
            leftComp.l = mergeComp->l;
            while (oldComp != mergeComp) {
                leftComp.maxV = max(leftComp.maxV, mergeComp->maxV);
                leftComp.minV = min(leftComp.minV, mergeComp->minV);
                mergeComp = comps.erase(mergeComp);
            }
        }
        oldComp = comps.erase(oldComp);
        if (rBound != ind + 1) {
            if (leftComp.minV >= after.second) {
                comps.insert({ind + 1, rBound, after.first, after.second});
                comps.insert(leftComp);
            } else {
                comps.insert({leftComp.l, rBound, min(leftComp.minV, after.first), max(leftComp.maxV, after.second)});
            }
        } else {
            comps.insert(leftComp);
        }
    } else {
        Component rightComp = {ind, rBound, min(val, after.first), max(val, after.second)};
        auto mergeComp = comps.lower_bound({lBound, -2, 0, val});
        if (mergeComp != comps.begin() && mergeComp != oldComp && val >= mergeComp->minV) {
            mergeComp--;
        }
        if (mergeComp != comps.end() && val < mergeComp->maxV && ind < mergeComp->l) {
            rightComp.r = mergeComp->r;
            while (oldComp != mergeComp) {
                rightComp.minV = min(rightComp.minV, oldComp->minV);
                rightComp.maxV = max(rightComp.maxV, oldComp->maxV);
                oldComp = comps.erase(oldComp);
            }
        }
        oldComp = comps.erase(oldComp);
        if (lBound != ind) {
            if (before.first >= rightComp.maxV) {
                comps.insert(rightComp);
                comps.insert({lBound, ind, before.first, before.second});
            } else {
                comps.insert({lBound, rightComp.r, min(before.first, rightComp.minV),
                              max(before.second, rightComp.maxV)});
            }
        } else {
            comps.insert(rightComp);
        }
    }
    return comps.size();
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> q;
    tree = Tree(n, pii(0, 0));
    a = vi(n, 0);
    comps.insert({0, n, 0, 0});
    for (int i = 0; i < n; i++) {
        cin >> a[i];
        update(i, a[i]);
    }
    for (int i = 0; i < q; i++) {
        int pos, val;
        cin >> pos >> val;
        cout << update(pos - 1, val) << "\n";
    }
    flush(cout);
    return 0;
}


# include <bits/stdc++.h>
//https://codeforces.com/contest/1270/problem/H
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
int n, q;
vi a;

typedef pii T;
static constexpr T unit = pii(INT_MAX, INT_MIN);

struct Tree {
    T f(T a, T b) { return pii(min(a.first, b.first), max(a.second, b.second)); }

    vector<T> s;
    int n;

    Tree(int n = 0, T def = unit) : s(static_cast<unsigned int>(2 * n), def), n(n) {}

    void update(int pos, T val) {
        for (s[pos += n] = val; pos /= 2;)
            s[pos] = f(s[pos * 2], s[pos * 2 + 1]);
    }

    T query(int b, int e) { // query [b, e)
        T ra = unit, rb = unit;
        for (b += n, e += n; b < e; b /= 2, e /= 2) {
            if (b % 2) ra = f(ra, s[b++]);
            if (e % 2) rb = f(s[--e], rb);
        }
        return f(ra, rb);
    }
} tree;

struct Component {
    int l, r, minV, maxV;

    bool operator<(Component o) const {
        // still a total ordering, but now we can search tree sets based on multiple keys
        if ((r == -1 || o.r == -1) && (minV != o.minV)) {
            return minV > o.minV;
        } else if ((r == -2 || o.r == -2) && (maxV != o.maxV)) {
            return maxV > o.maxV;
        } else if (l != o.l) {
            return l < o.l;
        } else {
            return r < o.r;
        }
    }
};

set<Component> comps;

void check() {
    for (Component c:comps) {
        assert(c.l < c.r);
        assert(c.minV <= c.maxV);
    }
    for (auto it = comps.begin(); it != comps.end();) {
        Component x = *it;
        Component y = *++it;
        if (it == comps.end()) {
            break;
        }
        assert(x.r == y.l);
        assert(x.minV >= y.maxV);
    }
}

int update(int ind, int val) {
    a[ind] = val;
    tree.update(ind, pii(val, val));
    // see if we destroy the component a belongs to
    auto oldComp = comps.upper_bound({ind, n, 0, 0});
    if (oldComp != comps.begin()) {
        oldComp--;
    }
    int rBound = oldComp->r, lBound = oldComp->l;
    pii before = tree.query(oldComp->l, ind);
    pii after = tree.query(ind + 1, oldComp->r);
    if (before.first < val && val < after.second) {
        return comps.size();
    }
    int res = tree.query(ind + 1, n).second;
    // no connection to the right side, merge left side
    if (val >= (after == unit ? INT_MAX : after.second) ||
        ((after == unit && (ind + 1 == n || val >= res))
        // also, a left merge will go all the way to the left
        && (before == unit ? INT_MIN : before.first) < val)) {
        Component leftComp = {lBound, ind + 1, min(val, before.first), max(val, before.second)};
        auto mergeComp = comps.upper_bound({lBound, -1, val, 0});
        if (mergeComp != comps.end() && val > mergeComp->minV && ind >= mergeComp->r) {
            leftComp.l = mergeComp->l;
            while (oldComp != mergeComp) {
                leftComp.maxV = max(leftComp.maxV, mergeComp->maxV);
                leftComp.minV = min(leftComp.minV, mergeComp->minV);
                mergeComp = comps.erase(mergeComp);
            }
        }
        oldComp = comps.erase(oldComp);
        if (rBound != ind + 1) {
            if (leftComp.minV >= after.second) {
                comps.insert({ind + 1, rBound, after.first, after.second});
                comps.insert(leftComp);
            } else {
                comps.insert({leftComp.l, rBound, min(leftComp.minV, after.first), max(leftComp.maxV, after.second)});
            }
        } else {
            comps.insert(leftComp);
        }
    } else {
        Component rightComp = {ind, rBound, min(val, after.first), max(val, after.second)};
        auto mergeComp = comps.lower_bound({lBound, -2, 0, val});
        if (mergeComp != comps.begin() && mergeComp != oldComp && val >= mergeComp->minV) {
            mergeComp--;
        }
        if (mergeComp != comps.end() && val < mergeComp->maxV && ind < mergeComp->l) {
            rightComp.r = mergeComp->r;
            while (oldComp != mergeComp) {
                rightComp.minV = min(rightComp.minV, oldComp->minV);
                rightComp.maxV = max(rightComp.maxV, oldComp->maxV);
                oldComp = comps.erase(oldComp);
            }
        }
        oldComp = comps.erase(oldComp);
        if (lBound != ind) {
            if (before.first >= rightComp.maxV) {
                comps.insert(rightComp);
                comps.insert({lBound, ind, before.first, before.second});
            } else {
                comps.insert({lBound, rightComp.r, min(before.first, rightComp.minV),
                              max(before.second, rightComp.maxV)});
            }
        } else {
            comps.insert(rightComp);
        }
    }
    return comps.size();
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> q;
    tree = Tree(n, pii(0, 0));
    a = vi(n, 0);
    comps.insert({0, n, 0, 0});
    for (int i = 0; i < n; i++) {
        cin >> a[i];
        update(i, a[i]);
    }
    for (int i = 0; i < q; i++) {
        int pos, val;
        cin >> pos >> val;
        cout << update(pos - 1, val) << endl;
        check();
    }
    flush(cout);
    return 0;
}


# include <bits/stdc++.h>
//https://codeforces.com/contest/1270/problem/H
using namespace std;
typedef pair<int, int> pii;
typedef vector<int> vi;
int n, q;
vi a;

typedef pii T;
static constexpr T unit = pii(INT_MAX, INT_MIN);

struct Tree {
    T f(T a, T b) { return pii(min(a.first, b.first), max(a.second, b.second)); }

    vector<T> s;
    int n;

    Tree(int n = 0, T def = unit) : s(static_cast<unsigned int>(2 * n), def), n(n) {}

    void update(int pos, T val) {
        for (s[pos += n] = val; pos /= 2;)
            s[pos] = f(s[pos * 2], s[pos * 2 + 1]);
    }

    T query(int b, int e) { // query [b, e)
        T ra = unit, rb = unit;
        for (b += n, e += n; b < e; b /= 2, e /= 2) {
            if (b % 2) ra = f(ra, s[b++]);
            if (e % 2) rb = f(s[--e], rb);
        }
        return f(ra, rb);
    }
} tree;

struct Component {
    int l, r, minV, maxV;

    bool operator<(Component o) const {
        // still a total ordering, but now we can search tree sets based on multiple keys
        if ((r == -1 || o.r == -1) && (minV != o.minV)) {
            return minV > o.minV;
        } else if ((r == -2 || o.r == -2) && (maxV != o.maxV)) {
            return maxV > o.maxV;
        } else if (l != o.l) {
            return l < o.l;
        } else {
            return r < o.r;
        }
    }
};

set<Component> comps;

void check() {
    for (Component c:comps) {
        assert(c.l < c.r);
        assert(c.minV <= c.maxV);
    }
    for (auto it = comps.begin(); it != comps.end();) {
        Component x = *it++;
        if (it == comps.end()) {
            break;
        }
        Component y = *it;
        assert(x.r == y.l);
        assert(x.minV >= y.maxV);
    }
}

void insertMerged(Component l, Component r){
    if(l.l == l.r){
        comps.insert(r);
    }else if(r.l == r.r){
        comps.insert(l);
    }else if(l.minV >= r.maxV){
        comps.insert(l);
        comps.insert(r);
    }else{
        comps.insert({l.l, r.r, min(l.minV, r.minV), max(l.maxV, r.maxV)});
    }
}
int update(int ind, int val) {
    a[ind] = val;
    tree.update(ind, pii(val, val));
    // see if we destroy the component a belongs to
    auto oldComp = comps.upper_bound({ind, n, 0, 0});
    if (oldComp != comps.begin()) {
        oldComp--;
    }
    int rBound = oldComp->r, lBound = oldComp->l;
    pii before = tree.query(oldComp->l, ind);
    pii after = tree.query(ind + 1, oldComp->r);
    if (before.first < val && val < after.second) {
        return comps.size();
    }
    // no connection to the right side
    if (val >= tree.query(ind + 1, n).second
         // also, a left merge will go all the way to the left
         && (before == unit || before.first < val)) {
        // merge left side
        Component leftComp = {lBound, ind + 1, min(val, before.first), max(val, before.second)};
        auto mergeComp = comps.upper_bound({lBound, -1, val, 0});
        if (mergeComp != comps.end() && val > mergeComp->minV && ind >= mergeComp->r) {
            leftComp.l = mergeComp->l;
            while (oldComp != mergeComp) {
                leftComp.maxV = max(leftComp.maxV, mergeComp->maxV);
                leftComp.minV = min(leftComp.minV, mergeComp->minV);
                mergeComp = comps.erase(mergeComp);
            }
        }
        comps.erase(oldComp);
        Component rComp = {ind + 1, rBound, after.first, after.second};
        insertMerged(leftComp, rComp);
    } else {
        Component rightComp = {ind, rBound, min(val, after.first), max(val, after.second)};
        auto mergeComp = comps.lower_bound({lBound, -2, 0, val});
        if ((mergeComp == comps.end()) ||
            (mergeComp != comps.begin() && mergeComp != oldComp && val >= mergeComp->minV)) {
            mergeComp--;
        }
        if (val < mergeComp->maxV && ind < mergeComp->l) {
            rightComp.r = mergeComp->r;
            while (oldComp != mergeComp) {
                oldComp = comps.erase(oldComp);
                rightComp.minV = min(rightComp.minV, oldComp->minV);
                rightComp.maxV = max(rightComp.maxV, oldComp->maxV);
            }
        }
        comps.erase(oldComp);
        Component lComp = {lBound, ind, before.first, before.second};
        insertMerged(lComp, rightComp);
    }
    return comps.size();
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> q;
    tree = Tree(n, pii(0, 0));
    a = vi(n, 0);
    comps.insert({0, n, 0, 0});
    for (int i = 0; i < n; i++) {
        cin >> a[i];
        update(i, a[i]);
    }
    for (int i = 0; i < q; i++) {
        int pos, val;
        cin >> pos >> val;
        cout << update(pos - 1, val) << endl;
    }
    flush(cout);
    return 0;
}


# include <bits/stdc++.h>
//https://codeforces.com/contest/1270/problem/H
using namespace std;
typedef pair<int, int> pii;
typedef vector<int> vi;
int n, q;
vi a;

typedef pii T;
static constexpr T unit = pii(INT_MAX, INT_MIN);

struct Tree {
    T f(T a, T b) { return pii(min(a.first, b.first), max(a.second, b.second)); }

    vector<T> s;
    int n;

    Tree(int n = 0, T def = unit) : s(static_cast<unsigned int>(2 * n), def), n(n) {}

    void update(int pos, T val) {
        for (s[pos += n] = val; pos /= 2;)
            s[pos] = f(s[pos * 2], s[pos * 2 + 1]);
    }

    T query(int b, int e) { // query [b, e)
        T ra = unit, rb = unit;
        for (b += n, e += n; b < e; b /= 2, e /= 2) {
            if (b % 2) ra = f(ra, s[b++]);
            if (e % 2) rb = f(s[--e], rb);
        }
        return f(ra, rb);
    }
} tree;

struct Component {
    int l, r, minV, maxV;

    bool operator<(Component o) const {
        // still a total ordering, but now we can search tree sets based on multiple keys
        if ((r == -1 || o.r == -1) && (minV != o.minV)) {
            return minV > o.minV;
        } else if ((r == -2 || o.r == -2) && (maxV != o.maxV)) {
            return maxV > o.maxV;
        } else if (l != o.l) {
            return l < o.l;
        } else {
            return r < o.r;
        }
    }
};

set<Component> comps;

void check() {
    for (Component c:comps) {
        assert(c.l < c.r);
        assert(c.minV <= c.maxV);
    }
    for (auto it = comps.begin(); it != comps.end();) {
        Component x = *it++;
        if (it == comps.end()) {
            break;
        }
        Component y = *it;
        assert(x.r == y.l);
        assert(x.minV >= y.maxV);
    }
}

int update(int ind, int val) {
    a[ind] = val;
    tree.update(ind, pii(val, val));
    // see if we destroy the component a belongs to
    auto oldComp = comps.upper_bound({ind, n, 0, 0});
    if (oldComp != comps.begin()) {
        oldComp--;
    }
    int rBound = oldComp->r, lBound = oldComp->l;
    pii before = tree.query(oldComp->l, ind);
    pii after = tree.query(ind + 1, oldComp->r);
    if (before.first < val && val < after.second) {
        return comps.size();
    }
    // no connection to the right side
    if (val >= tree.query(ind + 1, n).second
         // also, a left merge will go all the way to the left
         && (before == unit || before.first < val)) {
        // merge left side
        Component leftComp = {lBound, ind + 1, min(val, before.first), max(val, before.second)};
        auto mergeComp = comps.upper_bound({lBound, -1, val, 0});
        if (mergeComp != comps.end() && val > mergeComp->minV && ind >= mergeComp->r) {
            leftComp.l = mergeComp->l;
            while (oldComp != mergeComp) {
                leftComp.maxV = max(leftComp.maxV, mergeComp->maxV);
                leftComp.minV = min(leftComp.minV, mergeComp->minV);
                mergeComp = comps.erase(mergeComp);
            }
        }
        comps.erase(oldComp);
        if (rBound != ind + 1) {
            if (leftComp.minV >= after.second) {
                comps.insert(leftComp);
                comps.insert({ind + 1, rBound, after.first, after.second});
            } else {
                comps.insert({leftComp.l, rBound, min(leftComp.minV, after.first), max(leftComp.maxV, after.second)});
            }
        } else {
            comps.insert(leftComp);
        }
    } else {
        Component rightComp = {ind, rBound, min(val, after.first), max(val, after.second)};
        auto mergeComp = comps.lower_bound({lBound, -2, 0, val});
        if ((mergeComp == comps.end()) ||
            (mergeComp != comps.begin() && mergeComp != oldComp && val >= mergeComp->minV)) {
            mergeComp--;
        }
        if (mergeComp != comps.end() && val < mergeComp->maxV && ind < mergeComp->l) {
            rightComp.r = mergeComp->r;
            while (oldComp != mergeComp) {
                oldComp = comps.erase(oldComp);
                rightComp.minV = min(rightComp.minV, oldComp->minV);
                rightComp.maxV = max(rightComp.maxV, oldComp->maxV);
            }
        }
        comps.erase(oldComp);
        if (lBound != ind) {
            if (before.first >= rightComp.maxV) {
                comps.insert(rightComp);
                comps.insert({lBound, ind, before.first, before.second});
            } else {
                comps.insert({lBound, rightComp.r, min(before.first, rightComp.minV),
                              max(before.second, rightComp.maxV)});
            }
        } else {
            comps.insert(rightComp);
        }
    }
    return comps.size();
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> q;
    tree = Tree(n, pii(0, 0));
    a = vi(n, 0);
    comps.insert({0, n, 0, 0});
    for (int i = 0; i < n; i++) {
        cin >> a[i];
        update(i, a[i]);
    }
    for (int i = 0; i < q; i++) {
        int pos, val;
        cin >> pos >> val;
        cout << update(pos - 1, val) << endl;
        check();
    }
    flush(cout);
    return 0;
}


# include <bits/stdc++.h>
//https://codeforces.com/contest/1270/problem/H
using namespace std;
typedef pair<int, int> pii;
typedef vector<int> vi;
int n, q;
vi a;

typedef pii T;
static constexpr T unit = pii(INT_MAX, INT_MIN);

struct Tree {
    T f(T a, T b) { return pii(min(a.first, b.first), max(a.second, b.second)); }

    vector<T> s;
    int n;

    Tree(int n = 0, T def = unit) : s(static_cast<unsigned int>(2 * n), def), n(n) {}

    void update(int pos, T val) {
        for (s[pos += n] = val; pos /= 2;)
            s[pos] = f(s[pos * 2], s[pos * 2 + 1]);
    }

    T query(int b, int e) { // query [b, e)
        T ra = unit, rb = unit;
        for (b += n, e += n; b < e; b /= 2, e /= 2) {
            if (b % 2) ra = f(ra, s[b++]);
            if (e % 2) rb = f(s[--e], rb);
        }
        return f(ra, rb);
    }
} tree;

struct Component {
    int l, r, minV, maxV;

    bool operator<(Component o) const {
        // still a total ordering, but now we can search tree sets based on multiple keys
        if ((r == -1 || o.r == -1) && (minV != o.minV)) {
            return minV > o.minV;
        } else if ((r == -2 || o.r == -2) && (maxV != o.maxV)) {
            return maxV > o.maxV;
        } else if (l != o.l) {
            return l < o.l;
        } else {
            return r < o.r;
        }
    }
};

set<Component> comps;

void check() {
    for (Component c:comps) {
        assert(c.l < c.r);
        assert(c.minV <= c.maxV);
    }
    for (auto it = comps.begin(); it != comps.end();) {
        Component x = *it++;
        if (it == comps.end()) {
            break;
        }
        Component y = *it;
        assert(x.r == y.l);
        assert(x.minV >= y.maxV);
    }
}

int update(int ind, int val) {
    a[ind] = val;
    tree.update(ind, pii(val, val));
    // see if we destroy the component a belongs to
    auto oldComp = comps.upper_bound({ind, n, 0, 0});
    if (oldComp != comps.begin()) {
        oldComp--;
    }
    int rBound = oldComp->r, lBound = oldComp->l;
    pii before = tree.query(oldComp->l, ind);
    pii after = tree.query(ind + 1, oldComp->r);
    if (before.first < val && val < after.second) {
        return comps.size();
    }
    int res = tree.query(ind + 1, n).second;
    // no connection to the right side, merge left side
    if (after == unit && (ind + 1 == n || val >= res)
         // also, a left merge will go all the way to the left
         && (before == unit || before.first < val)) {
        Component leftComp = {lBound, ind + 1, min(val, before.first), max(val, before.second)};
        auto mergeComp = comps.upper_bound({lBound, -1, val, 0});
        if (mergeComp != comps.end() && val > mergeComp->minV && ind >= mergeComp->r) {
            leftComp.l = mergeComp->l;
            while (oldComp != mergeComp) {
                leftComp.maxV = max(leftComp.maxV, mergeComp->maxV);
                leftComp.minV = min(leftComp.minV, mergeComp->minV);
                mergeComp = comps.erase(mergeComp);
            }
        }
        comps.erase(oldComp);
        if (rBound != ind + 1) {
            if (leftComp.minV >= after.second) {
                comps.insert(leftComp);
                comps.insert({ind + 1, rBound, after.first, after.second});
            } else {
                comps.insert({leftComp.l, rBound, min(leftComp.minV, after.first), max(leftComp.maxV, after.second)});
            }
        } else {
            comps.insert(leftComp);
        }
    } else {
        Component rightComp = {ind, rBound, min(val, after.first), max(val, after.second)};
        auto mergeComp = comps.lower_bound({lBound, -2, 0, val});
        if ((mergeComp == comps.end()) ||
            (mergeComp != comps.begin() && mergeComp != oldComp && val >= mergeComp->minV)) {
            mergeComp--;
        }
        if (mergeComp != comps.end() && val < mergeComp->maxV && ind < mergeComp->l) {
            rightComp.r = mergeComp->r;
            while (oldComp != mergeComp) {
                rightComp.minV = min(rightComp.minV, oldComp->minV);
                rightComp.maxV = max(rightComp.maxV, oldComp->maxV);
                oldComp = comps.erase(oldComp);
            }
        }
        comps.erase(oldComp);
        if (lBound != ind) {
            if (before.first >= rightComp.maxV) {
                comps.insert(rightComp);
                comps.insert({lBound, ind, before.first, before.second});
            } else {
                comps.insert({lBound, rightComp.r, min(before.first, rightComp.minV),
                              max(before.second, rightComp.maxV)});
            }
        } else {
            comps.insert(rightComp);
        }
    }
    return comps.size();
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> q;
    tree = Tree(n, pii(0, 0));
    a = vi(n, 0);
    comps.insert({0, n, 0, 0});
    for (int i = 0; i < n; i++) {
        cin >> a[i];
        update(i, a[i]);
    }
    for (int i = 0; i < q; i++) {
        int pos, val;
        cin >> pos >> val;
        cout << update(pos - 1, val) << endl;
    }
    flush(cout);
    return 0;
}


# include <bits/stdc++.h>
//https://codeforces.com/contest/1270/problem/H
using namespace std;
typedef vector<int> vi;
int n, q;
vi arr;
int maxV = 1000001;

// f[i]: the number of values 1<=j<n  arr such that (arr[j]>=i-n) != (arr[j-1]>=i-n) if i > n, else min(f[2*i], f[2*i+1])
// count[i]: the number of values left<=j<right  arr such that f[i] == f[i-n] if i > n, else the number of times i-n appears in a.
struct SegTree {
    SegTree *l, *r;
    int lo, mid, hi, fLazy = 0, f = 0, count = 0;

    SegTree(int lo, int hi) : lo(lo), hi(hi) {
        mid = lo + (hi - lo) / 2;
        if (lo + 1 < hi) {
            l = new SegTree(lo, mid);
            r = new SegTree(mid, hi);
            merge();
        }
    }

    void merge() {
        assert(l->fLazy + r->fLazy == 0);
        f = min(l->f, r->f);
        count = 0;
        if (f == r->f) {
            count += r->count;
        }
        if (f == l->f) {
            count += l->count;
        }
    }

    void push() {
        assert(l + 1 != r);
        if (fLazy) {
            l->addF(lo, hi, fLazy), r->addF(lo, hi, fLazy), fLazy = 0;
        }
    }

    int query(int L, int R) {
        if (R <= lo || hi <= L) { return 0; }
        if (lo + 1 != hi) { push(); }
        if (L <= lo && hi <= R) { return f == 1 ? count : 0; }
        int ans = l->query(L, R) + r->query(L, R);
        merge();
        return ans;
    }

    void updCount(int ind, int diff) {
        if (ind == lo && hi == ind + 1) {
            count+= diff;
        } else {
            push();
            if (ind < mid) {
                l->updCount(ind, diff);
            } else {
                assert(ind < hi);
                r->updCount(ind, diff);
            }
            merge();
        }
    }

    void addF(int L, int R, int x) {
        if (R <= lo || hi <= L) return;
        if (L <= lo && hi <= R) {
            f += x;
            if (lo + 1 != hi) {
                fLazy += x;
                push();
            }
        } else {
            push(), l->addF(L, R, x), r->addF(L, R, x), merge();
        }
    }

    void upd(int a, int b, int delta) {
        addF(min(a, b), max(a, b), delta);
    }

    void addToTree(int pos, int add) {
        upd(arr[pos - 1], arr[pos], add);
        upd(arr[pos], arr[pos + 1], add);
        updCount(arr[pos], add);
    }

};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> q;
    arr = vi(n + 2, 0);
    for (int i = 1; i <= n; i++) {
        cin >> arr[i];
    }
    arr[0] = maxV;
    arr[n + 1] = 0;
    SegTree tree = SegTree(0, maxV);
    for (int i = 1; i <= n; i++) {
        tree.updCount(arr[i], 1);
    }
    for (int i = 0; i <= n; i++) {
        tree.upd(arr[i], arr[i + 1], 1);
    }
    for (int i = 0; i < q; i++) {
        int pos, val;
        cin >> pos >> val;
        tree.addToTree(pos, -1);
        arr[pos] = val;
        tree.addToTree(pos, 1);
        cout << tree.query(0, maxV) << "\n";
    }
    flush(cout);
    return 0;
}


# include <bits/stdc++.h>
//https://codeforces.com/contest/1270/problem/H
using namespace std;
# define rep(i, a, b) for(int i = a; i < (b); ++i)
# define trav(a, x) for(auto& a : x)
# define all(x) begin(x), end(x)
# define sz(x) (int)(x).size()
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
int n, q;
vi a;

typedef pii T;
static constexpr T unit = pii(INT_MAX, INT_MIN);

struct Tree {
    T f(T a, T b) { return pii(min(a.first, b.first), max(a.second, b.second)); }

    vector<T> s;
    int n;

    Tree(int n = 0, T def = unit) : s(static_cast<unsigned int>(2 * n), def), n(n) {}

    void update(int pos, T val) {
        for (s[pos += n] = val; pos /= 2;)
            s[pos] = f(s[pos * 2], s[pos * 2 + 1]);
    }

    T query(int b, int e) { // query [b, e)
        T ra = unit, rb = unit;
        for (b += n, e += n; b < e; b /= 2, e /= 2) {
            if (b % 2) ra = f(ra, s[b++]);
            if (e % 2) rb = f(s[--e], rb);
        }
        return f(ra, rb);
    }
} tree;

struct Component {
    int l, r, minV, maxV;

    bool operator<(Component o) const {
        // still a total ordering, but now we can search tree sets based on multiple keys
        if ((r == -1 || o.r == -1) && (minV != o.minV)) {
            return minV > o.minV;
        } else if ((r == -2 || o.r == -2) && (maxV != o.maxV)) {
            return maxV > o.maxV;
        } else if (l != o.l) {
            return l < o.l;
        } else {
            return r < o.r;
        }
    }
};

set<Component> comps;

int update(int ind, int val) {
    a[ind] = val;
    tree.update(ind, pii(val, val));
    // see if we destroy the component a belongs to
    auto oldComp = comps.lower_bound({ind, 0, 0, 0});
    if (oldComp != comps.begin() && oldComp->l > ind) {
        oldComp--;
    }
    int rBound = oldComp->r, lBound = oldComp->l;
    pii before = tree.query(oldComp->l, ind);
    pii after = tree.query(ind + 1, oldComp->r);
    // no connection to the right side, merge left side
    if (val >= (after.second == INT_MIN ? INT_MAX : after.second) ||
        (after == unit && ind + 1 != n && val >= tree.query(ind + 1, n).second)) {
        Component leftComp = {lBound, ind + 1, min(val, before.first), max(val, before.second)};
        // find the maximal component with a max value less than val, merge everything with left comp
        auto mergeComp = comps.upper_bound({lBound, -2, 0, val});
        if (mergeComp != oldComp && mergeComp != comps.end() && val > mergeComp->maxV && ind >= mergeComp->r) {
            leftComp.l = mergeComp->l;
            while (oldComp != mergeComp) {
                mergeComp = comps.erase(mergeComp);
                leftComp.maxV = max(leftComp.maxV, mergeComp->maxV);
                leftComp.minV = min(leftComp.minV, mergeComp->minV);
            }
        }
        oldComp = comps.erase(oldComp);
        comps.insert(leftComp);
        if (rBound != ind + 1) {
            comps.insert({ind + 1, rBound, after.first, after.second});
        }
    } else {
        Component rightComp = {ind, rBound, min(val, after.first), max(val, after.second)};
        // find minimal component with a min value more than val
        auto mergeComp = comps.lower_bound({lBound, -1, val, 0});
        if (mergeComp != comps.begin()) {
            mergeComp--;
        }
        if (mergeComp != comps.end() && val < mergeComp->minV && ind < mergeComp->l) {
            rightComp.r = mergeComp->r;
            while (oldComp != mergeComp) {
                rightComp.minV = min(rightComp.minV, oldComp->minV);
                rightComp.maxV = max(rightComp.maxV, oldComp->maxV);
                oldComp = comps.erase(oldComp);
            }
        }
        oldComp = comps.erase(oldComp);
        if (lBound != ind) {
            comps.insert({lBound, ind, before.first, before.second});
        }
        comps.insert(rightComp);
    }
    return comps.size();
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> q;
    tree = Tree(n, pii(0, 0));
    a = vi(n, 0);
    comps.insert({0, n, 0, 0});
    for (int i = 0; i < n; i++) {
        cin >> a[i];
        update(i, a[i]);
    }
    for (int i = 0; i < q; i++) {
        int pos, val;
        cin >> pos >> val;
        cout << update(pos - 1, val) << "\n";
    }
    return 0;
}


# include <bits/stdc++.h>
//https://codeforces.com/contest/1270/problem/H
using namespace std;
typedef pair<int, int> pii;
typedef vector<int> vi;
int n, q;
vi a;

typedef pii T;
static constexpr T unit = pii(INT_MAX, INT_MIN);

struct Tree {
    T f(T a, T b) { return pii(min(a.first, b.first), max(a.second, b.second)); }

    vector<T> s;
    int n;

    Tree(int n = 0, T def = unit) : s(static_cast<unsigned int>(2 * n), def), n(n) {}

    void update(int pos, T val) {
        for (s[pos += n] = val; pos /= 2;)
            s[pos] = f(s[pos * 2], s[pos * 2 + 1]);
    }

    T query(int b, int e) { // query [b, e)
        T ra = unit, rb = unit;
        for (b += n, e += n; b < e; b /= 2, e /= 2) {
            if (b % 2) ra = f(ra, s[b++]);
            if (e % 2) rb = f(s[--e], rb);
        }
        return f(ra, rb);
    }
} tree;

struct Component {
    int l, r, minV, maxV;

    bool operator<(Component o) const {
        // still a total ordering, but now we can search tree sets based on multiple keys
        if ((r == -1 || o.r == -1) && (minV != o.minV)) {
            return minV > o.minV;
        } else if ((r == -2 || o.r == -2) && (maxV != o.maxV)) {
            return maxV > o.maxV;
        } else if (l != o.l) {
            return l < o.l;
        } else {
            return r < o.r;
        }
    }
};

set<Component> comps;

void check() {
    for (Component c:comps) {
        assert(c.l < c.r);
        assert(c.minV <= c.maxV);
    }
    for (auto it = comps.begin(); it != comps.end();) {
        Component x = *it++;
        if (it == comps.end()) {
            break;
        }
        Component y = *it;
        assert(x.r == y.l);
        assert(x.minV >= y.maxV);
    }
}

void insertMerged(Component l, Component r){
    if(l.l == l.r){
        comps.insert(r);
    }else if(r.l == r.r){
        comps.insert(l);
    }else if(l.minV >= r.maxV){
        comps.insert(l);
        comps.insert(r);
    }else{
        comps.insert({l.l, r.r, min(l.minV, r.minV), max(l.maxV, r.maxV)});
    }
}
int update(int ind, int val) {
    a[ind] = val;
    tree.update(ind, pii(val, val));
    // see if we destroy the component a belongs to
    auto oldComp = comps.upper_bound({ind, n, 0, 0});
    if (oldComp != comps.begin()) {
        oldComp--;
    }
    int rBound = oldComp->r, lBound = oldComp->l;
    pii before = tree.query(oldComp->l, ind);
    pii after = tree.query(ind + 1, oldComp->r);
    if (before.first < val && val < after.second) {
        return comps.size();
    }
    // no connection to the right side
    if (val >= tree.query(ind + 1, n).second
         // also, a left merge will go all the way to the left
         && (before == unit || before.first < val)) {
        // merge left side
        Component leftComp = {lBound, ind + 1, min(val, before.first), max(val, before.second)};
        auto mergeComp = comps.upper_bound({lBound, -1, val, 0});
        if (mergeComp != comps.end() && val > mergeComp->minV && ind >= mergeComp->r) {
            leftComp.l = mergeComp->l;
            while (oldComp != mergeComp) {
                leftComp.maxV = max(leftComp.maxV, mergeComp->maxV);
                leftComp.minV = min(leftComp.minV, mergeComp->minV);
                mergeComp = comps.erase(mergeComp);
            }
        }
        comps.erase(oldComp);
        Component rComp = {ind + 1, rBound, after.first, after.second};
        insertMerged(leftComp, rComp);
    } else {
        Component rightComp = {ind, rBound, min(val, after.first), max(val, after.second)};
        auto mergeComp = comps.lower_bound({ind, -2, 0, val});
        if ((mergeComp == comps.end()) ||
            (mergeComp != comps.begin() && mergeComp != oldComp && val >= mergeComp->minV)) {
            mergeComp--;
        }
        if (val < mergeComp->maxV && ind < mergeComp->l) {
            rightComp.r = mergeComp->r;
            while (oldComp != mergeComp) {
                oldComp = comps.erase(oldComp);
                rightComp.minV = min(rightComp.minV, oldComp->minV);
                rightComp.maxV = max(rightComp.maxV, oldComp->maxV);
            }
        }
        comps.erase(oldComp);
        Component lComp = {lBound, ind, before.first, before.second};
        insertMerged(lComp, rightComp);
    }
    return comps.size();
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> q;
    tree = Tree(n, pii(0, 0));
    a = vi(n, 0);
    comps.insert({0, n, 0, 0});
    for (int i = 0; i < n; i++) {
        cin >> a[i];
        update(i, a[i]);
    }
    for (int i = 0; i < q; i++) {
        int pos, val;
        cin >> pos >> val;
        cout << update(pos - 1, val) << endl;
    }
    flush(cout);
    return 0;
}