zoukankan      html  css  js  c++  java
  • [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
    */ 
    
  • 相关阅读:
    redisTemplate写哈希表遇到的坑
    embedded-redis在单元测试中的使用
    使用Standford coreNLP进行中文命名实体识别
    字符编码和文件编码
    Elasticsearch提示low disk watermark [85%] exceeded on [UTyrLH40Q9uIzHzX-yMFXg][Sonofelice][/Users/baidu/Documents/work/soft/data/nodes/0] free: 15.2gb[13.4%], replicas will not be assigned to this node
    nginx.conf常用配置解析
    使用nginx搭建文件下载服务器
    lua连接数据库操作示例代码
    spring常见注解说明
    lua相关库安装常见问题
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/11235775.html
Copyright © 2011-2022 走看看