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


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

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

     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值可能是非零的,甚至影响更新,导致错误。

    总结

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

  • 相关阅读:
    经典分水岭算法的 C++ 实现
    一个简易的键盘按键测试程序
    工程优化方法中的“最速下降法”和“DFP拟牛顿法”的 C 语言实现
    基于哈夫曼编码的压缩解压程序(C 语言)
    博客选择:博客园 or CSDN
    Spring总结
    CSS总结
    EL表达式总结
    Jdbc总结
    hibernate总结
  • 原文地址:https://www.cnblogs.com/CaptainSlow/p/9250970.html
Copyright © 2020-2023  润新知