线段树维护单调栈
在普通单调栈的基础上支持修改操作,动态维护节点的单调信息,重点是必须具有可合并性
陶陶摘苹果:
每次向序列最后里加一个数,问每次加入的单调递增的栈的长度(从1开始,1必须选)
就是说eps精度误差不要乱用,如果判等要用至少1e-14,搞个1e-6会WA50%
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<bitset>
#include<map>
#include<vector>
#include<deque>
#include<queue>
#define _f(i,a,b) for(register int i=a;i<=b;++i)
#define f_(i,a,b) for(register int i=a;i>=b;--i)
#define INF 2147483647
#define chu printf
#define ll long long
#define rint register int
#define ull unsigned long long
using namespace std;
inline int re()
{
int x=0,h=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')h=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*h;
}
const int maxn=1e5+100;
#define eps 1e-14
struct node
{
int ls,rs,len;
double k;//
}e[maxn*4];int tot;
double ai[maxn];
#define rson e[rt].rs
#define lson e[rt].ls
inline int calc(int rt,int l,int r,double dik)//l--r区间内确定最小值大于(y/x)的区间长度
{
// if(!rt)return 0;//如果没有这个区间(一个数都没有就return 0)
if(e[rt].k<=dik)return 0;
if(ai[l]>dik)return e[rt].len;
if(l==r)return e[rt].k>dik;
int mid=(l+r)>>1;
if(dik>=e[lson].k)return calc(rson,mid+1,r,dik);
return calc(lson,l,mid,dik)+e[rt].len-e[lson].len;//这里一定注意,rson的贡献产生于对于整个l--r区间来说,而不是mid+1,r的区间
}
inline void Insert(int &rt,int l,int r,int pos,int x,int y)//在pos位置添加一个y/x的斜率同时维护最值
{
if(!rt)rt=++tot;
if(l==r)
{
e[rt].len=1;
e[rt].k=(double)y/x;
return;
}
int mid=(l+r)>>1;
if(pos<=mid)Insert(lson,l,mid,pos,x,y);
else Insert(rson,mid+1,r,pos,x,y);//先更新最值
//然后考虑区间合并
e[rt].k=max(e[lson].k,e[rson].k);
e[rt].len=e[lson].len+calc(rson,mid+1,r,e[lson].k);
// chu("%d--%d的len:%d\n",l,r,e[rt].len);
}
int n,m,root;
int main()
{
// freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
n=re(),m=re();
_f(i,1,m)
{
int ix=re(),iy=re();
ai[ix]=(double)iy/ix;
Insert(root,1,n,ix,ix,iy);
chu("%d\n",e[root].len);
}
return 0;
}
/*
3 4
2 4
3 6
1 1000000000
1 1
1
1
1
2
5 6
2 5
3 7
4 5
1 2
2 3
3 4
*/