BZOJ 2957: 楼房重建
线段树维护当前区间的答案和当前区间的最大值
考虑如何合并
左区间的答案显然可以被统计进去,记左区间的最大值为val
考虑右区间,右区间的左儿子的最大值<=val,则直接计算右区间的右儿子
否则右区间的右儿子的答案肯定能被计入最终答案,计算左儿子即可
递归统计
O(n log^2 n)
也可以分块(wu nao)
#include<cstdio> #include<algorithm> using namespace std; int n,m,sz[550005],x[100005],y[100005]; double Max[550005]; int update(int t,int l,int r,double lim){ if (l==r) return Max[t]>lim; int mid=(l+r)>>1; if (Max[t<<1]<=lim) return update(t<<1|1,mid+1,r,lim); else return sz[t]-sz[t<<1]+update(t<<1,l,mid,lim); } void insert(int t,int l,int r,int x,double k){ if (l==r){ sz[t]=1; Max[t]=k; return; } int mid=(l+r)>>1; if (x<=mid) insert(t<<1,l,mid,x,k); else insert(t<<1|1,mid+1,r,x,k); Max[t]=max(Max[t<<1],Max[t<<1|1]); sz[t]=sz[t<<1]+update(t<<1|1,mid+1,r,Max[t<<1]); } int main(){ scanf("%d%d",&n,&m); for (int i=1; i<=m; i++) scanf("%d%d",&x[i],&y[i]); for (int i=1; i<=m; i++){ insert(1,1,n,x[i],(double)y[i]/x[i]); printf("%d\n",sz[1]); } return 0; }