题目描述
/*
思路非常巧妙的一道题
不难看出线段树维护的是区间内每个点与原点连线的斜率的最大值
考虑合并区间时怎么合并答案
左区间一定会被看到,右区间能被看到的一定大于左区间的最大值
所以可以查询右区间中大于左区间最大值的数的个数来向上合并
每次修改的复杂度为log^2n
*/
#include<complex>
#include<cstdio>
using namespace std;
const int N=1e5+7;
int n,m;
int Siz[N<<2];
double Max[N<<2];
int qread()
{
int x=0;
char ch=getchar();
while(ch<'0' || ch>'9')ch=getchar();
while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x;
}
int Calc(int l,int r,int rt,double v)
{
if(Max[rt]<=v)return 0;
if(l==r)return Max[rt]>v;
int mid=l+r>>1;
if(Max[rt<<1]<=v)return Calc(mid+1,r,rt<<1|1,v);
return Calc(l,mid,rt<<1,v)+Siz[rt]-Siz[rt<<1];
}
void Modify(int l,int r,int rt,int p,double v)
{
if(l==r)
{
Max[rt]=v;Siz[rt]=1;
return;
}
int mid=l+r>>1;
if(p<=mid)Modify(l,mid,rt<<1,p,v);
else Modify(mid+1,r,rt<<1|1,p,v);
Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
Siz[rt]=Siz[rt<<1]+Calc(mid+1,r,rt<<1|1,Max[rt<<1]);
}
int main()
{
scanf("%d%d",&n,&m);
int x,y;
while(m--)
{
x=qread();y=qread();
Modify(1,n,1,x,1.0*y/x);
printf("%d
",Siz[1]);
}
return 0;
}