zoukankan      html  css  js  c++  java
  • 【bzoj2957】楼房重建 分块+二分查找

    题目描述

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

    输入

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

    输出

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

    样例输入

    3 4
    2 4
    3 6
    1 1000000000
    1 1

    样例输出

    1
    1
    1
    2


    题解

    线段树 分块+二分查找

    题目大意说白了就是给定n个斜率,求这些斜率的连续递增数列(从1开始,每有一个比前一个大的就选定)的长度,多次修改。

    看了下数据范围可以分块求。

    先暴力搞定每个块的递增数列,把这些斜率从小到大塞到一个栈里边(时间复杂度O(n/b),b为块的大小)。

    然后查找时从头开始,在每个块对应的栈中二分查找第一个斜率比前一个大的位置,这个位置和栈里面后边的位置都能被看到(时间复杂度O(blog(n/b)))。

    总时间复杂度为O(n*(n/b + blog(n/b)))≈O(n*(n/b + blogn))。

    这样一来b=√(n/logn)比较合算,但其实也没什么卵用,直接√n一块就行。

    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #define N 100010
    using namespace std;
    int n , si , h[N];
    struct data
    {
        int top , sta[400];
    }a[400];
    bool cmp(int a , int b)
    {
        if(!b) return h[a] > 0;
        return (long long)h[a] * b > (long long)h[b] * a;
    }
    int main()
    {
        int m , i , si , p , l , r , mid , ans , tmp , last;
        scanf("%d%d" , &n , &m) , n ++ ;
        si = (int)sqrt(n);
        while(m -- )
        {
            scanf("%d" , &p);
            scanf("%d" , &h[p]);
            l = p / si * si , r = min(n , (p / si + 1) * si);
            a[p / si].top = 0;
            for(i = l ; i < r ; i ++ )
                if(cmp(i , a[p / si].sta[a[p / si].top]))
                    a[p / si].sta[++a[p / si].top] = i;
            ans = 0 , last = 0;
            for(i = 0 ; i <= (n - 1) / si ; i ++ )
            {
                l = 1 , r = a[i].top , tmp = 0;
                while(l <= r)
                {
                    mid = (l + r) >> 1;
                    if(cmp(a[i].sta[mid] , last)) tmp = mid , r = mid - 1;
                    else l = mid + 1; 
                }
                if(tmp) last = a[i].sta[a[i].top] , ans += a[i].top - tmp + 1;
            }
            printf("%d
    " , ans);
        }
        return 0;
    }

     

  • 相关阅读:
    PyCharm使用(完全图解(最新经典))
    pg存储过程学习
    sql_to_sqlalchemy
    python中嵌入lua解析器
    Python和lua互相调用
    Lupa
    [cb] Unity Editor 添加右键菜单
    [C#] 委托之Action和Func区别
    [反编译U3D]Decompile Unity Resources
    [cb] Assetbundle打包(一)
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6756312.html
Copyright © 2011-2022 走看看