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

    题意:给定序列,每次修改一个值,求前缀最大值的个数。

    解:线段树经典应用。

    每个节点维护最大值和该区间前缀最大值个数。

    发现我们不用下传标记,只需要合并区间。

    需要实现一个函数int ask([l r] lm)求出区间[l r]中前一个数是lm时前缀最大值个数。

    那么当lm >= large[ls]时,return ask([mid r] lm)

    这个很好理解,左子区间的所有数都不会成为前缀最大值。

    当lm < large[ls]时,return ask([l mid] lm) + (sum[o] - sum[ls])

    这个注意,不是sum[rs]因为sum[rs]的意义是从0开始,而这个的前面会有large[ls]挡着,所以是sum[o] - sum[ls]

    修改的时候先一路到底把large值改了。然后return的时候把沿途区间都更新。

    具体来说就是sum[o] = ask([l r] 0)...等等,好像有问题。

    lm < large[ls]的时候,求值是要调用sum[o]的,这不就循环调用导致出错了吗?

    所以写成sum[o] = sum[ls] + ask([mid r] large[ls])即可。

    本题不用建树。需要建树的时候就跟修改类似的写法即可。

     1 #include <cstdio>
     2 #include <algorithm>
     3 
     4 const int N = 100010;
     5 
     6 double a[N], large[N << 2];
     7 int n, sum[N << 2];
     8 
     9 int ask(int l, int r, int o, double lm) {
    10     if(l == r) {
    11         return (lm < a[r]);
    12     }
    13     int mid = (l + r) >> 1;
    14     if(lm > large[o << 1]) {
    15         return ask(mid + 1, r, o << 1 | 1, lm);
    16     }
    17     else {
    18         return sum[o] - sum[o << 1] + ask(l, mid, o << 1, lm);
    19     }
    20 }
    21 
    22 void change(int p, double v, int l, int r, int o) {
    23     if(l == r) {
    24         large[o] = v;
    25         sum[o] = 1;
    26         return;
    27     }
    28     int mid = (l + r) >> 1;
    29     if(p <= mid) {
    30         change(p, v, l, mid, o << 1);
    31     }
    32     else {
    33         change(p, v, mid + 1, r, o << 1 | 1);
    34     }
    35     large[o] = std::max(large[o << 1], large[o << 1 | 1]);
    36     sum[o] = sum[o << 1] + ask(mid + 1, r, o << 1 | 1, large[o << 1]);
    37     return;
    38 }
    39 
    40 int main() {
    41     int m;
    42     scanf("%d%d", &n, &m);
    43     for(int i = 1, x, y; i <= m; i++) {
    44         scanf("%d%d", &x, &y);
    45         a[x] = (double)(y) / x;
    46         change(x, a[x], 1, n, 1);
    47         printf("%d
    ", sum[1]);
    48     }
    49 
    50     return 0;
    51 }
    AC代码
  • 相关阅读:
    Mysql 去重
    深入理解ob_flush和flush的区别
    Yii2 基础模板前后台登录分离
    Yii2 登录报错
    使用 php 内部web服务器
    SQL 分组后,获取每组中的最大值对应的数据
    跨域访问解决方案
    Spring Boot对静态资源的映射规则
    Spring Boot项目的探究
    Spring Boot项目的不同启动方式
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10325023.html
Copyright © 2011-2022 走看看