[BZOJ 2957]楼房重建

题目描述

动态地维护一个以斜率为关键字的最长严格上升子序列。

解法

对于修改操作,只影响一个块,每次修改都暴力重构一下,计算出每个斜率并按块内斜率排序,最后存入一个vector中(其实并不需要排序,因为本身插入的时候就是按照“单调递增——小了就跳过,大了就插入并更新斜率最大值”)单次修改时间复杂度 \(O(\sqrt{n})\)

inline void modify(int x,int y){
    double maxx=0;//斜率最大值
        num[x]=y;//赋值
    c[pos[x]].clear();//暴力重构
    for(int i=(pos[x]-1)*s+1;i<=pos[x]*s&&i<=n;i++){
        if(!num[i]) continue;//如果当前的位置没有楼房就跳过
        double ret=((double)num[i]/(1.0*i));//计算斜率
        if(maxx<ret) c[pos[x]].push_back(ret),maxx=ret;//插入数列,并更新max
    }
/*    for(vector<double>::iterator it=c[pos[x]].begin();it!=c[pos[x]].end();it++)
        printf("%.3lf ",*it);
    printf("\n");*/
}

对于查询操作,枚举每一个块,在块内二分上一个块的斜率最大值(即当前块内能看到的楼房的斜率最小值),累计上答案。单次查询 \(O(\sqrt{n})\)


inline int query_(int x,double val){
    return c[x].end()-upper_bound(c[x].begin(),c[x].end(),val);//返回块内大于val的数的个数
}

inline int query(){
    int ans=0;
    double maxx=(double)num[st]/st;//st表示第一个的楼房的位置
    for(int i=1;i<=pos[n];i++){
        ans+=query_(i,maxx);//在块内二分
        if(c[i].empty()) continue;//当前块没有楼房就跳过
        double ret=(*(--c[i].end()));//当前块的最大值(因为块内是有序的,所以最后一个数就是当前块的最大值)
        if(maxx<ret) maxx=ret;//更新最大值
    }
    return ans+1;//第一个楼房没算,所以要+1
}

时间复杂度 \(O(m\)\sqrt{n})\()\)

#include<stdio.h>
#include<math.h>
#include<vector>
#include<algorithm>
using namespace std;
#define N 100007
#define sqN 1007

template<class T>
inline void read(T &x){
    x=0;char c=getchar();T flag=1;
    while(c<'0'||c>'9'){if(c=='-')flag=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    x*=flag;
}

vector<double> c[sqN];
int s,n,m,pos[N],num[N],st;

inline int min(int x,int y){return x<y? x:y;}
inline int max(int x,int y){return x>y? x:y;}
inline void modify(int x,int y){
    double maxx=0;num[x]=y;
    c[pos[x]].clear();
    for(int i=(pos[x]-1)*s+1;i<=pos[x]*s&&i<=n;i++){
        if(!num[i]) continue;
        double ret=((double)num[i]/(1.0*i));
        if(maxx<ret) c[pos[x]].push_back(ret),maxx=ret;
    }
/*    for(vector<double>::iterator it=c[pos[x]].begin();it!=c[pos[x]].end();it++)
        printf("%.3lf ",*it);
    printf("\n");*/
}
inline int query_(int x,double val){
    return c[x].end()-upper_bound(c[x].begin(),c[x].end(),val);
}
inline int query(){
    int ans=0;
    double maxx=(double)num[st]/st;
    for(int i=1;i<=pos[n];i++){
        ans+=query_(i,maxx);
        if(c[i].empty()) continue;
        double ret=(*(--c[i].end()));
        if(maxx<ret) maxx=ret;
    }
    return ans+1;
}
int main(){
//    freopen("data.in","r",stdin);
//    freopen("mine.out","w",stdout);
    read(n),read(m),s=(int)(sqrt(n)+0.5),st=n+1;
    for(int i=1;i<=n;i++) pos[i]=(i-1)/s+1;
    int x,y;
    while(m--){
        read(x);read(y);
        st=min(st,x);modify(x,y);
        printf("%d\n",query());
    }
}
/*
5 7
4 6
3 2
1 19
5 11
2 17
1 1
1 1
*/ 
posted @ 2019-07-24 09:09  Kreap  阅读(154)  评论(0编辑  收藏  举报