/*
线段树做法:对于线段树每个结点维护两个值:ans和maxl,
ans表示只考虑这个区间的可视区间的答案,maxl表示这个区间的最大斜率。
那么问题的关键就在于如何合并两个区间,显然左区间的答案肯定可以作为总区间的答案,
那么接下来就是看右区间有多少个在新加入左区间的约束后是可行的。
考虑如果右区间最大值都小于等于左区间最大值那么右区间就没有贡献了,相当于是被整个挡住了。
如果大于最大值,就再考虑右区间的两个子区间:左子区间、右子区间,
加入左子区间的最大值小于等于左区间最大值,那么就递归处理右子区间;
否则就递归处理左子区间,然后加上右子区间原本的答案。
考虑这样做的必然性:因为加入左区间最高的比左子区间最高的矮,
那么相当于是左区间对于右子区间没有约束,都是左子区间产生的约束。
但是右子区间的答案要用右区间答案-左子区间答案,
不能直接调用右子区间本身答案,因为其本身答案没有考虑左子区间的约束。
*/
#include<iostream>
#include<algorithm>
#include<cstdio>
#define N 100010
using namespace std;
int n,m;
struct node
{
double mx;
int sum,l,r;
}tr[N<<2];
void build(int now,int l,int r)
{
tr[now].l=l;tr[now].r=r;
if(l==r) return;
int mid=(l+r)>>1;
build(now<<1,l,mid);build(now<<1|1,mid+1,r);
}
int calc(double k,int now)
{
if(tr[now].l==tr[now].r) return tr[now].mx>k;
if(tr[now<<1].mx>k)
return calc(k,now<<1)+tr[now].sum-tr[now<<1].sum;
else return calc(k,now<<1|1);
}
inline void pushup(int now)
{
tr[now].mx=max(tr[now<<1].mx,tr[now<<1|1].mx);
tr[now].sum=tr[now<<1].sum+calc(tr[now<<1].mx,now<<1|1);
}
void change(int now,int pos,double c)
{
if(tr[now].l==tr[now].r)
{
tr[now].mx=c;
tr[now].sum=1;
return;
}
int mid=(tr[now].l+tr[now].r)>>1;
if(pos<=mid) change(now<<1,pos,c);
else change(now<<1|1,pos,c);
pushup(now);
}
int main()
{
scanf("%d%d",&n,&m);
build(1,1,n);
for(int i=1;i<=m;i++)
{
double x,y;
scanf("%lf%lf",&x,&y);
change(1,(int)x,y/x);
printf("%d\n",tr[1].sum);
}
return 0;
}