zoukankan      html  css  js  c++  java
  • LG 题解 P4198 楼房重建

    [TOC]

    前置芝士

    • 线段树

    Description

    一共有 (n) 栋楼,小明坐在 ((0,0)),第 (i) 栋楼房用 ((i,h_i)) 表示。有 (m) 次修改,每次修改一栋楼的高度,可能变高或边矮,修改后输出小明能看到楼的数量。

    Solution

    稍微分析一下就能得出我们要求一个最长上升的斜率。

    考虑如何维护这个看起来不可维护东西。

    下面的表示方式可能有所不适,但这是我能想到的一种最清晰的表达方式了

    我们设 (mx[l,r]) 表示 ([l,r]) 区间斜率的最大值,(len[l,r]) 表示 ([l,r]) 区间最长合法长度,(k_{i}) 表示第 (i) 栋楼的斜率。

    假设当前我们要更新区间 ([l,r]),更小的区间已经被更新了。

    (mid) 为分解点,(midr) 为区间 ((mid,r]) 的分解点,(lm = mx[l,mid])

    显然左区间的 (len[l,mid]) 每次都要选,我们用递归函数 (Queryr(mid+1,r)) 表示递归去处理 ((mid,r]) 区间(右区间)的结果。

    递归时:

    • 如果 (lm ge mx(mid, midr]),那么返回 (Queryr(midr+1,r))。这个右区间的左区间已经不能选了。
    • 否则,返回 (Queryr(mid+1,midr) + len(mid,r] - len(midr,r])。右区间的左区间的最大值比 (lm) 还大,说明右区间的右区间都能选上,但右区间的左区间不确定,需要递归求解。

    下面是几个结束条件:

    • 如果 (lm > mx(mid,r]),那么 (len[l,r] = len[l,mid])。考虑实际意义,左边的楼房把右边的全挡住了,右边的就都看不到了。
    • 如果 (lm < k_{mid+1}),那么 (len[l,r] = len[l,mid] + len(mid,r])。在右区间中,如果第一栋楼都能被看见,那么右区间能看到的楼在 (l) 处都能看见。
    • 如果右区间长度为 (1),直接判断 (lm)(k_r) 的关系即可。

    实现细节看代码吧。

    Code

    /*
    Work by: Suzt_ilymics
    Problem: 不知名屑题
    Knowledge: 垃圾算法
    Time: O(能过)
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define LL long long
    #define orz cout<<"lkp AK IOI!"<<endl
    
    using namespace std;
    const int MAXN = 2e5+5;
    const int INF = 1e9+7;
    const int mod = 1e9+7;
    
    int n, m;
    double a[MAXN];
    
    int read(){
        int s = 0, f = 0;
        char ch = getchar();
        while(!isdigit(ch))  f |= (ch == '-'), ch = getchar();
        while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
        return f ? -s : s;
    }
    
    namespace Seg {
        #define lson i << 1
        #define rson i << 1 | 1
        struct Tree {
            int len; double max;
        }tree[MAXN << 2];
        void Push_up(int i) { tree[i].max = max(tree[lson].max, tree[rson].max); }
        int Queryr(int i, int l, int r, double lmax) {
            if(tree[i].max <= lmax) return 0;
            if(a[l] > lmax) return tree[i].len;
            if(l == r) return a[l] > lmax;
            int mid = (l + r) >> 1;
            if(tree[lson].max <= lmax) return Queryr(rson, mid + 1, r, lmax);
            else return Queryr(lson, l, mid, lmax) + (tree[i].len - tree[lson].len);
        }
        void Modify(int i, int l, int r, int L, int R, int val) {
            if(L <= l && r <= R) {
                tree[i].max = (1.0 * val / L);
                tree[i].len = 1;
                return ;
            }
            int mid = (l + r) >> 1;
            if(mid >= L) Modify(lson, l, mid, L, R, val);
            if(mid < R) Modify(rson, mid + 1, r, L, R, val);
            Push_up(i);
            tree[i].len = tree[lson].len + Queryr(rson, mid + 1, r, tree[lson].max);
        }
    }
    
    int main()
    {
        n = read(), m = read();
        for(int i = 1, l, r; i <= m; ++i) {
            l = read(), r = read();
            a[l] = (1.0 * r / l);
            Seg::Modify(1, 1, n, l, l, r);
            printf("%d
    ", Seg::tree[1].len);
        }
        return 0;
    }
    
  • 相关阅读:
    (转)使用 PyInstaller 把python程序 .py转为 .exe 可执行程序
    (转)使用 python Matplotlib 库绘图
    使用Matplotlib画图系列(一)
    Numpy常用金融计算(一)
    Windows中安装Linux子系统的详细步骤
    Centos7+Postfix+Dovecot实现内网邮件收发 风行天下
    centos7系统防火墙端口转发 风行天下
    Centos7+Postfix+Dovecot实现内网邮件收发
    centos7的路径含有空格Linux命令使用时路径存在空格、特殊符号(如、@等等) 风行天下
    zabbix无法使用Detect operating system [zabbix] 风行天下
  • 原文地址:https://www.cnblogs.com/Silymtics/p/solution-P4198.html
Copyright © 2011-2022 走看看