楼房重建 HYSBZ - 2957;
分块大法好啊>>分块大法妙啊>>太6了>>太暴力了
分块的思路:维护每一块的上升子序列>>该子序列中以斜率为值进行维护>>
每次更新楼房高度,需要暴力更新该块的上升子序列
每次查询答案:以上一块的最大斜率为起点值>>二分查找>>拼接起来
复杂度是sqrt(n)*log(sqrt(n))
所以总复杂度是>>m*sqrt(n)log(sqrt(n));
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int n,m,x,y,blo,cnt;
int bel[N],l[500],r[500],num[500],ans;
double b[N];
double s[500][500];
void build(){
cnt=n/blo;if(n%blo) cnt++;
for(int i=1;i<=n;i++) bel[i]=(i-1)/blo+1;
for(int i=1;i<=cnt;i++) l[i]=(i-1)*blo+1,r[i]=min(i*blo,n);
}
void update(int x,int y){
b[x]=1.0*y/x;
x=bel[x];num[x]=0;double last=0;
for(int i=l[x];i<=r[x];i++) if(b[i]>last){
num[x]++;s[x][num[x]]=b[i];last=b[i];
}
last=s[1][num[1]];ans=num[1];
for(int i=2;i<=cnt;i++){
int pos=upper_bound(s[i]+1,s[i]+num[i]+1,last)-s[i];
if(pos>num[i]||pos<1) continue;
last=max(last,s[i][num[i]]);
ans+=(num[i]-pos+1);
}
}
int main(){
scanf("%d%d",&n,&m);blo=sqrt(n);
build();
for(int i=1;i<=n;i++) bel[i]=(i-1)/blo+1;
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
update(x,y);
printf("%d\n",ans);
}
return 0;
}