单点修改,维护从左看到的斜率升序序列长度。
每个楼房的高度除以距离得到斜率。
所以看出这道题需要动态维护一个单调上升序列。
考虑区间合并。记录区间答案长度以及区间最大值。
很明显左区间仍然可以被看到。而右区间不一定。
右区间能别看到的,只有右区间合法答案中,比左区间最大值还大的部分。
考虑在右区间上二分。因为右区间维护的也是一个单调栈,所以可以二分。
如果到叶子节点,判断是否大于左区间最大值。
如果当前左区间最大值大于要求最大值,则返回在左区间中查找的答案加上,本区间长度减去左区间长度。
注意,此时不应该直接提取右边答案。因为我们需要的,是在本区间单调栈中,属于右边的部分,而非仅考虑右边的答案。这是有区别的。
剩下的大家都很熟悉,二分就是了。
在每次单点修改后,区间长度就是左区间长度加上,在右区间中,大于左区间最大值的长度。
#include<bits/stdc++.h>
using namespace std;
#define in read()
int in{
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){
ch=getchar();if(ch=='-')f=-1;
}
while(isdigit(ch)){
cnt=cnt*10+ch-48;ch=getchar();
}return cnt*f;
}
int n,m;
struct node{
int len,l,r;
double maxx;
}t[400003];
void build(int u,int l,int r){
t[u].l=l;t[u].r=r;if(l==r)return;
int mid=(l+r)>>1;build(u*2,l,mid);build(u*2+1,mid+1,r);
}
double a[100003];
void pushup(int u){
t[u].maxx=max(t[u*2].maxx,t[u*2+1].maxx);
}
int pushup2(int u,double key){
if(t[u].l==t[u].r)return t[u].maxx>key;
if(t[u].maxx<=key)return 0;
if(a[t[u].l]>key)return t[u].len;
if(t[u*2].maxx>key)return t[u].len-t[u*2].len+pushup2(u*2,key);
else return pushup2(u*2+1,key);
}
void modify(int u,int pos,double key){
if(t[u].l>pos||t[u].r<pos)return;
if(t[u].l==t[u].r&&t[u].r==pos){
t[u].maxx=key;t[u].len=1;return;
}
modify(u*2,pos,key);modify(u*2+1,pos,key);
pushup(u);
t[u].len=t[u*2].len+pushup2(u*2+1,t[u*2].maxx);
}
signed main(){
n=in;m=in;
build(1,1,n);
while(m--){
int x=in;int y=in;a[x]=(double)y/x;
modify(1,x,a[x]);
cout<<t[1].len<<'\n';
}
return 0;
}