zoukankan      html  css  js  c++  java
  • 楼房重建

    https://www.luogu.org/blog/violet2333/p4198-lou-fang-zhong-jian

    题目描述

    小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


    emmm~~

    经过艰辛万苦,终于弄懂题解啦做出来了。

    当然,也有dalao的指导~

    线段树维护 序列中的最大斜率,序列长度(即能够看见的楼房个数);

    pushup1:更新区间最大的斜率;

    pushup2:更新区间的序列长度;

    • 修改后

      更新每一个区间的最大斜率和长度(划重点);

    • pushup2

      ①左儿子最大斜率≥右儿子最大斜率:

      右儿子全部舍掉

      ②左儿子最大斜率<右儿子的左端点的斜率:

      ∴左儿子对右儿子没有影响,直接返回右儿子的序列长度即可

      ③右儿子只有一个元素: 还用教吗?

      ④不满足以上,左儿子最大斜率<右儿子最大斜率:

      递归右儿子。
      简称 右儿子的左儿子 为 右左儿子,
           右儿子的右儿子 为 右右儿子。
      如果右左儿子最大斜率≤左儿子的最大斜率。只递归右右儿子即可。
      否则递归右左儿子的序列长度+右儿子序列长度-右左儿子的序列长度。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 100005;
    struct node {
        double mx;
        int len;  //序列中的最大斜率,序列长度
    } t[N << 2];
    int n, m;
    double a[N];  // i点的斜率
    
    void pushup1(int u) { //更新大区间的最大斜率
        t[u].mx = max(t[u << 1].mx, t[u << 1 | 1].mx); 
    }
    
    int pushup2(double lmx, int u, int l, int r) {
        if (t[u].mx <= lmx)
            return 0;  //如果左儿子最大斜率>右儿子最大斜率,右边全部舍掉
        if (a[l] > lmx)
            return t[u].len;  //如果右儿子中左端点斜率>左儿子最大斜率,返回右儿子区间长度即可
        if (l == r)
            return a[l] > lmx;  //如果只有一个元素,判断该元素斜率与左儿子最大斜率的大小,返回1/0即可;
        int mid = (l + r) >> 1;            //拆分右儿子,继续递归
        int s1 = u << 1, s2 = u << 1 | 1;  //(大区间右儿子的)左儿子,右儿子
        if (t[s1].mx <= lmx)
            return pushup2(lmx, s2, mid + 1, r);
        else
            return pushup2(lmx, s1, l, mid) + t[u].len - t[s1].len;
    }
    
    void change(int u, int l, int r, int x, int y) {
        if (l == r && l == x) {  //序列中只有一个元素
            t[u].mx = (double)y / x;
            t[u].len = 1;
            return;
        }
        int mid = l + r >> 1;
        if (x <= mid)
            change(u << 1, l, mid, x, y);
        if (x > mid)
            change(u << 1 | 1, mid + 1, r, x, y);
        pushup1(u);
        t[u].len = t[u << 1].len + pushup2(t[u << 1].mx, u << 1 | 1, mid + 1, r);  //更新大区间的序列长度
        /*左儿子序列一定都在大区间中;
        ∵右儿子会受到左儿子的影响
        ∴递归右儿子,更新右儿子中可以看到的数量,加入大区间长度中
        */
    }
    
    int main() {
        scanf("%d%d", &n, &m);
        while (m--) {
            int x, y;
            scanf("%d%d", &x, &y);
            a[x] = (double)y / x;      //存入斜率
            change(1, 1, n, x, y);     //修改
            printf("%d
    ", t[1].len);  //输出序列长度
        }
    }
  • 相关阅读:
    centos、mac的grafana安装和简单使用
    通过k8s(Kubernetes)搭建jmeter的压测环境master-slave架构,实现弹性伸缩
    burpsuite破解版
    jvm调优
    火狐firefox、谷歌chrome等浏览器扩展、插件介绍
    关于Chrome谷歌浏览器开发者工具网络Network中返回无数据的问题
    微博登录过程分析
    SQL SERVER大话存储结构(4)_复合索引与包含索引
    千万级别数据表,单列索引和多列索引性能对比
    Showplan 逻辑运算符和物理运算符参考
  • 原文地址:https://www.cnblogs.com/aprincess/p/11626937.html
Copyright © 2011-2022 走看看