• [BZOJ29957] 楼房重建


    2957: 楼房重建

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 3294  Solved: 1554
    [Submit][Status][Discuss]

    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
     

     
    题解:
    那线段树维护区间的最大斜率和斜率最长上升子序列的长度;
    甚至建树都不需要;
    唯一的问题就是update,我们好像不可以O(1)合并。
    我们把一个序列分为左右两端记为L, R;
    如果R的最大斜率小于L的最大斜率,那么有区间直接就不用考虑了;
    如果R的最大斜率大于L的最大斜率,那么我们二分R区间,像这样递归下去;
     

     
    Code:
    #include <iostream>
    #include <cstdio>
    using namespace std;
    
    struct segment
    {
        int len;
        long double mx;
    }t[400010];
    #define ls(o) o<<1
    #define rs(o) o<<1|1
    #define mx(o) t[o].mx
    #define len(o) t[o].len
    
    inline int count(int l, int r, int o, long double hi)
    {
        if (l == r) return mx(o) > hi;
        int mid = l + r >> 1;
        if (mx(ls(o)) <= hi) return count(mid + 1, r, rs(o), hi);
        return len(o) - len(ls(o)) + count(l, mid, ls(o), hi);
    }
    
    inline void change(int l, int r, int o, int to, long double k)
    {
        if (l == r) 
        {
            len(o) = 1;
            mx(o) = k;
            return ;
        }
        int mid = l + r >> 1;
        if (to <= mid) change(l, mid, ls(o), to, k);
        else change(mid + 1, r, rs(o), to, k);
        mx(o) = max(mx(ls(o)), mx(rs(o)));
        len(o) = len(ls(o)) + count(mid + 1, r, rs(o), mx(ls(o)));
    }
    
    int main()
    {    
        int n, m;
        scanf("%d%d", &n, &m);
        while (m--)
        {
            int x, y;
            scanf("%d%d", &x, &y);
            change(1, n, 1, x, (long double)y / x);
            printf("%d
    ", len(1));
        }
        return 0;
    }
  • 相关阅读:
    ARPG手游实战练习(八)
    ARPG手游实战练习(七)
    ARPG手游实战练习(六)
    ARPG手游实战练习(五)
    ARPG手游实战练习(四)
    ARPG手游实战练习(三)
    C# Array类的Sort()方法
    C#继承讲解以及对象的创建
    单例模式
    愤怒的小鸟(练习版)
  • 原文地址:https://www.cnblogs.com/BriMon/p/9260062.html
Copyright © 2020-2023  润新知