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
    */ 
    
  • 相关阅读:
    【算法笔记】B1020 月饼
    JZOJ 3412. 【NOIP2013模拟】KC看星
    JZOJ 3517. 空间航行
    JZOJ 3515. 软件公司
    JZOJ 3514. 最小比例
    JZOJ 3490. 旅游(travel)
    luogu P3178 [HAOI2015]树上操作
    JZOJ 3427. 归途与征程
    JZOJ 3426. 封印一击
    JZOJ 3425. 能量获取
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/11235775.html
Copyright © 2011-2022 走看看