[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 }
View Code

 

posted @ 2019-08-07 19:55  PYWBKTDA  阅读(38)  评论(0编辑  收藏