[bzoj2957]楼房重建
令ai=Hi/i,那么即求有多少ai满足对于任意0<j<i,都有aj<ai,可以理解为强制选择的LIS,以下简称LIS2。
考虑分块,块内维护最大ai和块内的LIS2(具体的),然后不断枚举块并二分找到该块的LIS2中第一个大于曾经的max的值,并修改答案和max即可。
还有一种线段树的做法,即维护区间的最大ai和该区间内LIS2的长度,考虑区间的合并:最大的ai直接合并,LIS2可以直接累计上左区间的长度,然后暴力询问右区间,总时间复杂度为$o(nlog_{2}^{2}n)$
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 400005 4 #define L (k<<1) 5 #define R (L+1) 6 #define mid (l+r>>1) 7 int n,m,x,y,f[N]; 8 double ma[N]; 9 int query(int k,int l,int r,double x){ 10 if (l==r)return ma[k]>x; 11 if (ma[L]<=x)return query(R,mid+1,r,x); 12 return f[k]-f[L]+query(L,l,mid,x); 13 } 14 void update(int k,int l,int r,int x,double y){ 15 if (l==r){ 16 f[k]=1; 17 ma[k]=y; 18 return; 19 } 20 if (x<=mid)update(L,l,mid,x,y); 21 else update(R,mid+1,r,x,y); 22 ma[k]=max(ma[L],ma[R]); 23 f[k]=f[L]+query(R,mid+1,r,ma[L]); 24 } 25 int main(){ 26 scanf("%d%d",&n,&m); 27 for(int i=1;i<=m;i++){ 28 scanf("%d%d",&x,&y); 29 update(1,1,n,x,1.0*y/x); 30 printf("%d\n",f[1]); 31 } 32 }