• 谈谈今天写线段树时碰到的问题


    今天打一个线段树,求区间最值的。

    它有一个这样的更新函数定义:

     1 int insert(int rt, int l, int r) {
     2     if (r <= O || l >= D) return 0;
     3     if (O <= l && r <= D) {
     4         tree[rt].val += N;
     5         tree[rt].mark += N;
     6         return tree[rt].val;
     7     }
     8     int mid = (l + r) >> 1;
     9     pushdown(rt);
    10     return tree[rt].val = std::max(insert(lson, l, mid), insert(rson, mid, r));
    11 }

    注意10行return的写法。

    以及下面一个同样功能的函数定义:

     1 void insert(int rt, int l, int r) {
     2     if (r <= O || l >= D) return;
     3     if (O <= l && r <= D) {
     4         tree[rt].val += N;
     5         tree[rt].mark += N;
     6         return;
     7     }
     8     int mid = (l + r) >> 1;
     9     pushdown(rt);
    10     insert(lson, l, mid);
    11     insert(rson, mid, r);
    12     tree[rt].val = std::max(tree[lson].val, tree[rson].val);
    13 }

    它们达到的目的表面上看是相同的。但实际评测时,正是因为这两个函数的写法不同,导致了答案不一样。

    后者的结果时正确的。

    而如果这么写,也是错的:
    错误定义1:

     1 int insert(int rt, int l, int r) {
     2     if (r <= O || l >= D) return 0;
     3     if (O <= l && r <= D) {
     4         tree[rt].val += N;
     5         tree[rt].mark += N;
     6         return tree[rt].val;
     7     }
     8     int mid = (l + r) >> 1;
     9     pushdown(rt);
    10     int tmp1 = insert(lson, l, mid), tmp2 = insert(rson, mid, r);
    11     return tree[rt].val = std::max(tmp1, tmp2);
    12 }

    错误定义2:

     1 int insert(int rt, int l, int r) {
     2     if (r <= O || l >= D) return 0;
     3     if (O <= l && r <= D) {
     4         tree[rt].val += N;
     5         tree[rt].mark += N;
     6         return tree[rt].val;
     7     }
     8     int mid = (l + r) >> 1;
     9     pushdown(rt);
    10     int tmp1 = insert(lson, l, mid), tmp2 = insert(rson, mid, r);
    11     tree[rt].val = std::max(tmp1, tmp2);
    12     return tree[rt].val;
    13 }

    后来,我思考了很久,终于发现了错误的原因所在:

    注意它们都有一条相同的语句:

    if (r <= O || l >= D) return 0;

    正是因为这一条语句,当该节点所代表的区间不完全被更新区间包含时,会访问其左右子节点,在处理完其左右节点时,若有一个节点代表的区间与更新区间的交集为空,那么该节点的上传的val值就会被0所覆盖,而实际上这个节点的val值可能是非零的,甚至影响更新,导致错误。

    总结

    比赛时,这种问题非常难考虑到, 因为表面上看这样写确实是正确的。因此仔细考虑程序的每一个步骤。

  • 相关阅读:
    十九:数字排重
    十八:十六进制转八进制
    Dubbo Notes
    Concurrent Package
    MySQL(8.0)官方文档阅读笔记
    MyBatis笔记
    分布式事务
    RabbitMQ笔记
    Kafka官方文档阅读笔记
    Cassandra Note
  • 原文地址:https://www.cnblogs.com/CaptainSlow/p/9250970.html
Copyright © 2020-2023  润新知