• bzoj 2957 楼房重建 分块


    楼房重建

    Time Limit: 1 Sec  Memory Limit: 256 MB

    题目连接

    http://www.lydsy.com/JudgeOnline/problem.php?id=2957

    Description

    小A的楼房外有一大片施工工地,工地上有N栋待建的楼房。每天,这片工地上的房子拆了又建、建了又拆。他经常无聊地看着窗外发呆,数自己能够看到多少栋房子。
      为了简化问题,我们考虑这些事件发生在一个二维平面上。小A在平面上(0,0)点的位置,第i栋楼房可以用一条连接(i,0)和(i,Hi)的线段表 示,其中Hi为第i栋楼房的高度。如果这栋楼房上任何一个高度大于0的点与(0,0)的连线没有与之前的线段相交,那么这栋楼房就被认为是可见的。
      施工队的建造总共进行了M天。初始时,所有楼房都还没有开始建造,它们的高度均为0。在第i天,建筑队将会将横坐标为Xi的房屋的高度变为Yi(高度 可以比原来大---修建,也可以比原来小---拆除,甚至可以保持不变---建筑队这天什么事也没做)。请你帮小A数数每天在建筑队完工之后,他能看到多 少栋楼房?

    Input

      第一行两个正整数N,M
      接下来M行,每行两个正整数Xi,Yi

    Output

    M行,第i行一个整数表示第i天过后小A能看到的楼房有多少栋

    Sample Input


    3 4

    2 4

    3 6

    1 1000000000

    1 1

    Sample Output

    1

    1

    1

    2

    数据约定

      对于所有的数据1<=Xi<=N,1<=Yi<=10^9

    N,M<=100000

    HINT

    题意

     

    题解:

    首先这道题肯定是得转化成斜率来做,我们只有后面的斜率大于前面的斜率的时候,才能看见

    我们分块做,首先我们得明确,在每一个块中,斜率大小一定是单调的

    所以我们可以在每一个块中,都二分找到分界点,然后直接加上去就好了

    代码:

    //qscqesze
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <ctime>
    #include <iostream>
    #include <algorithm>
    #include <set>
    #include <vector>
    #include <sstream>
    #include <queue>
    #include <typeinfo>
    #include <fstream>
    #include <map>
    #include <stack>
    typedef long long ll;
    using namespace std;
    //freopen("D.in","r",stdin);
    //freopen("D.out","w",stdout);
    #define sspeed ios_base::sync_with_stdio(0);cin.tie(0)
    #define maxn 200001
    #define mod 10007
    #define eps 1e-9
    int Res,Num;char C,CH[12];
    //const int inf=0x7fffffff;   //无限大
    const int inf=0x3f3f3f3f;
    /*
    
    inline void P(int x)
    {
        Num=0;if(!x){putchar('0');puts("");return;}
        while(x>0)CH[++Num]=x%10,x/=10;
        while(Num)putchar(CH[Num--]+48);
        puts("");
    }
    */
    //**************************************************************************************
    inline ll read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void P(int x)
    {
        Num=0;if(!x){putchar('0');puts("");return;}
        while(x>0)CH[++Num]=x%10,x/=10;
        while(Num)putchar(CH[Num--]+48);
        puts("");
    }
    
    int n,m,sum,sz;
    int a,b;
    int num[maxn];
    double k[maxn];
    double maxv[maxn];
    vector<double> see[500];
    int l[500],r[500];
    
    void makeblock()
    {
        memset(maxv,0,sizeof(maxv));
        sz=sqrt((double)n*1.05);
        for(sum=1;sum*sz<n;sum++)
        {
            l[sum]=(sum-1)*sz+1;
            r[sum]=sum*sz;
            for(int i=l[sum];i<=r[sum];i++) num[i]=sum;
        }
        l[sum]=sz*(sum-1)+1;
        r[sum]=n;
        for(int i=l[sum];i<=r[sum];i++) num[i]=sum;
    }
    
    void updata()
    {
        double aa=a,bb=b;
        k[a]=bb/aa;
        maxv[num[a]]=0;
        see[num[a]].clear();
        double tmp=0;
        for(int i=l[num[a]];i<=r[num[a]];i++)
        {
            if(k[i]>maxv[num[a]])
            {
                maxv[num[a]]=k[i];
                see[num[a]].push_back(k[i]);
            }
        }
    }
    void query()
    {
        int ans=0;
        double tmp=0;
        for(int i=1;i<=sum;i++)
        {
            if(!see[i].empty())
            {
                ans+=see[i].end()-upper_bound(see[i].begin(),see[i].end(),tmp);
                tmp=max(tmp,maxv[i]);
            }
        }
        P(ans);
    }
    int main()
    {
        n=read(),m=read();
        makeblock();
        while(m--)
        {
            scanf("%d%d",&a,&b);
            updata();
            query();
        }
    }
  • 相关阅读:
    python3-while与if
    python3-while与continue
    python3-password在输入密码时隐藏密码
    input与字符串格式化
    for与break的用法
    bochs 2.6.8 常用命令集合
    关于8086中的jmp near ptr原理
    如何学习Python课程
    微信公众号去除密码安全提示
    模块的使用
  • 原文地址:https://www.cnblogs.com/qscqesze/p/4441225.html
Copyright © 2020-2023  润新知