• 洛谷P4198 楼房重建 (分块)


    洛谷P4198 楼房重建

    题目描述

    小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能看到的楼房有多少栋

    输入输出样例

    输入样例#1:

    3 4
    2 4
    3 6
    1 1000000000
    1 1

    输出样例#1:

    1
    1
    1
    2

    说明

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

    N,M<=100000

    Solution

    我们发现能看见的楼房的个数,就是这些楼房的斜率的最长上升子序列的长度,可以线段树维护,也可以分块,但是分块要慢得多

    博主在这里讲一下分块的做法,线段树以后再补?

    设有两个点a,b,高度分别为h[a],h[b],如果a不会被b阻挡,必有(frac{h[a]}{a}>=frac{h[b]}{b}),化为乘法形式为(h[a] imes b>=h[b] imes a),特别的,对于原点,我们特判一下,h[a]是不是大于0就可以了

    对于修改,我们暴力更新本块内元素信息,每次清零,重新维护一个块内最长上升子序列的长度,时间复杂度(O(sqrt n))

    对于查询,设last为上一个满足条件的块的末尾节点,我们每次从块1开始,一直到最后一块,在块内二分查找(因为是最长上升子序列,所以满足单调性)与last相比刚刚满足条件的点,那么从这个点开始一直到块末都是合法的序列,把答案加上这一段区间的长度,然后把last更新为本块末尾,继续上述操作
    时间复杂度(O(sqrt n))

    然而这样是会T的,我们把块的大小改为(sqrt {frac{n imes log(n)}{2}})会有奇效,但是记得数组大小也要相应更改

    Code

    #include<bits/stdc++.h>
    #define rg register
    #define lol long long
    #define il extern inline
    #define Min(a,b) (a)<(b)?(a):(b)
    #define Max(a,b) (a)>(b)?(a):(b)
    #define in(i) (i=read())
    using namespace std;
    const lol N=1e5+10;
    int read() {
        int ans=0,f=1; char i=getchar();
        while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
        while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+i-'0',i=getchar();
        return ans*f;
    }
    
    int n,m,blo,h[N],pos[N];
    struct Stack {
        int s[N],top;
    }t[330];
    il bool check(lol a,lol b) {
        if(!b) return h[a]>0;
        return (lol)(h[a]*b)>(lol)(h[b]*a);
    }
    
    void print(int x) {
        if(x>9) print(x/10);
        putchar(x%10+'0');
    }
    
    int main() {
        in(n),in(m); blo=sqrt(n*log(n)/2);
        for(rg int i=1;i<=n;i++) pos[i]=(i-1)/blo+1;
        while(m--) {
            int x,ans=0; in(x),in(h[x]);
            rg int l=(pos[x]-1)*blo+1,r=Min(n,pos[x]*blo);
            t[pos[x]].top=0;
            for(rg int i=l;i<=r;i++)
                if(check(i,t[pos[x]].s[t[pos[x]].top]))
                    t[pos[x]].s[++t[pos[x]].top]=i;//用一个栈来维护
            for(rg int i=1,last=0;i<=pos[n];i++) {
                rg int AQ=0; l=1,r=t[i].top;
                while(l<=r) {
                    int mid=l+r>>1;
                    if(check(t[i].s[mid],last)) AQ=mid,r=mid-1;
                    else l=mid+1;
                }
                if(AQ) last=t[i].s[t[i].top],ans+=t[i].top-AQ+1;
            }print(ans),putchar('
    ');
        }
    }
    
  • 相关阅读:
    idea的tomcat配置
    idea设置类文件的头部信息
    设置idea注释颜色
    Idea设置字体
    python 全栈开发,Day11(函数名应用,闭包,装饰器初识,带参数以及带返回值的装饰器)
    python 全栈开发,Day10(动态参数,命名空间,作用域,函数嵌套)
    python 全栈开发,Day9(函数的初始,返回值,传参,三元运算)
    python 全栈开发,Day8(文件操作)
    python 全栈开发,Day7(元组转换,列表以及字典的坑,集合,关系测试,深浅copy,编码补充)
    python 全栈开发,Day6补充(is,小数据池,编码转换)
  • 原文地址:https://www.cnblogs.com/real-l/p/9769092.html
Copyright © 2020-2023  润新知