【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\n" , ans);
    }
    return 0;
}

 

posted @ 2017-04-24 12:49  GXZlegend  阅读(329)  评论(0编辑  收藏