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

    不错的一道题。

    题意:每次修改一栋楼,求这些楼顶跟原点$(0,0)$的斜率单调上升长度(不是$ ext{LIS}$)。

    因为一个楼房能被看到可以等价于它的斜率比之前的任何一个都大。

    这道题实际上满足区间合并,但是比较麻烦。

    重点就在$ ext{pushup}$的写法。

    首先定义线段树中区间的解即为该对应区间内的单调上升长度。

    两个区间的合并:

    如图,发现右区间会受左区间的影响。

    左区间的答案为$3$,右区间的答案为$2$,但在合并后为$3$。

    而这样的话合并后为$4$。

    所以右区间的答案主要受左区间最大值的影响。

    令$cnt[o]$为结点$o$的答案,所以维护中一定有$cnt[o]=cnt[lson]+get\_ans(cnt[rson])$。

    如何$get\_ans$呢?

    发现右区间受左区间最大值影响,所以一定受到$maxv[lson]$的约束。

    观察如下

    如果$B$受到$A$的约束,那么$C$、$D$也会受到$A$的约束。然后$D$也会受到$C$的约束。

    如果$D$受到的约束中$A$没有$C$强,即$maxv[A]<maxv[C]$,那么只需递归处理$C$的区间再加上$D$贡献的答案(这里有个小细节,放后面谈)。

    因为区间$A,C$中最高的仍为$maxv[C]$。

    反之只需递归处理$D$区间,答案无需加上$C$(因为都被$A$挡住了)。

    当递归到边界了,也就只剩一个数了$maxv$,只要判断是否大于约束即可(解为$0//1$)

    递归过程中不需要修改$cnt$,因为区间内无需考虑区间外的影响(要想明白)。

    根据以上可以得到下面的$ ext{pushup}$:

    1 int pushup(int o, int l, int r, double d) {
    2     if (l == r) return maxv[o]-d > 1e-10 ? 1: 0;
    3     int mid = (l + r) >> 1;
    4     if (maxv[lson]-d > 1e-10) { // l > d
    5         return pushup(lson, l, mid, d) + cnt[o] - cnt[lson];
    6     } else { // l <= d
    7         return pushup(rson, mid+1, r, d);
    8     }
    9 }

    $d$表示约束,递归时需要下传。

    上面谈到了一个问题:加上$D$贡献的答案。

    这里是

    return pushup(lson, l, mid, d) + cnt[o] - cnt[lson];

    而不是

     return pushup(lson, l, mid, d) + cnt[rson];

    要理解两者的差别:

    后者是右区间不受左区间约束下的解;而前者是约束后的解$-$左区间的解(因为在一个区间内右区间一定受左区间约束),剩下的一定是约束后的右区间的解。

    单点修改时,维护$maxv$时维护区间的$cnt$(这里因为数值的修改包括在区间中,要对$cnt$进行修改)

    也就是:

    cnt[o] = cnt[lson] + pushup(rson, mid+1, r, maxv[lson]);

    于是问题就解决了。

    复杂度分析:单点修改$O(log n)$,一次$ ext{pushup}$需要$O(log n)$,所以一次的复杂度为$O(log^2n)$。

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 #define re register
     6 #define rep(i, a, b) for (re int i = a; i <= b; ++i)
     7 #define repd(i, a, b) for (re int i = a; i >= b; --i)
     8 #define For(i, a, b, s) for (re int i = a; i <= b; s)
     9 #define maxx(a, b) a = max(a, b)
    10 #define minn(a, b) a = min(a, b)
    11 #define LL long long
    12 #define INF (1 << 30)
    13 
    14 inline int read() {
    15     int w = 0, f = 1; char c = getchar();
    16     while (!isdigit(c)) f = c == '-' ? -1 : f, c = getchar();
    17     while (isdigit(c)) w = (w << 3) + (w << 1) + (c ^ '0'), c = getchar();
    18     return w * f;
    19 }
    20 
    21 const int maxn = 1e5 + 5, N = 100000;
    22 
    23 double a[maxn];
    24 
    25 struct SegT {
    26 #define lson (o << 1)
    27 #define rson (o << 1 | 1)
    28     double maxv[maxn << 2];
    29     int cnt[maxn << 2];
    30     void build(int o, int l, int r) {
    31         if (l == r) { cnt[o] = 1; return; }
    32         int mid = (l + r) >> 1;
    33         build(lson, l, mid); build(rson, mid+1, r);
    34     }
    35     void maintain(int o) { maxv[o] = max(maxv[lson], maxv[rson]); }
    36     int pushup(int o, int l, int r, double d) {
    37         if (l == r) return maxv[o]-d > 1e-10 ? 1: 0;
    38         int mid = (l + r) >> 1;
    39         if (maxv[lson]-d > 1e-10) { // l > o
    40             return pushup(lson, l, mid, d) + cnt[o] - cnt[lson];
    41         } else { // l <= o
    42             return pushup(rson, mid+1, r, d);
    43         }
    44     }
    45     void modify(int o, int l, int r, int x, int y) {
    46         if (l == r) {
    47             maxv[o] = (double)y / x;
    48             cnt[o] = y ? 1 : 0;
    49             return;
    50         }
    51         int mid = (l + r) >> 1;
    52         if (x <= mid) modify(lson, l, mid, x, y); else modify(rson, mid+1, r, x, y);
    53         maintain(o);
    54         cnt[o] = cnt[lson] + pushup(rson, mid+1, r, maxv[lson]);
    55     }
    56 } T;
    57 
    58 int n, m;
    59 int x, y;
    60 
    61 int main() {
    62     n = read(); m = read();
    63     rep(i, 1, m) {
    64         x = read(), y = read();
    65         T.modify(1, 1, N, x, y);
    66         printf("%d
    ", T.cnt[1]);
    67     }
    68     return 0;
    69 }
  • 相关阅读:
    QFramework 使用指南 2020(二):下载与版本介绍
    QFramework 使用指南 2020 (一): 概述
    Unity 游戏框架搭建 2018 (二) 单例的模板与最佳实践
    Unity 游戏框架搭建 2018 (一) 架构、框架与 QFramework 简介
    Unity 游戏框架搭建 2017 (二十三) 重构小工具 Platform
    Unity 游戏框架搭建 2017 (二十二) 简易引用计数器
    Unity 游戏框架搭建 2017 (二十一) 使用对象池时的一些细节
    你确定你会写 Dockerfile 吗?
    小白学 Python 爬虫(8):网页基础
    老司机大型车祸现场
  • 原文地址:https://www.cnblogs.com/ac-evil/p/10541520.html
Copyright © 2011-2022 走看看