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 }
  • 相关阅读:
    (转载) MTK芯片不开机必杀全攻略
    <19> MTK10A 修改模拟时钟表盘、表针的显示模式
    (转载) MTK flash
    (转载) MTK申请内存
    (转载) 标准C中的字符串操作函数
    pcb布线时线宽与耐流的关系
    (转载) vb6的数据类型
    (转载) MTK驱动开放基础知识
    (转载) MTK常用函数及宏定义
    xx了Windows正版验证
  • 原文地址:https://www.cnblogs.com/ac-evil/p/10541520.html
Copyright © 2011-2022 走看看