zoukankan      html  css  js  c++  java
  • 谈谈今天写线段树时碰到的问题

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

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

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

    总结

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

  • 相关阅读:
    如何用jquery实现实时监控浏览器宽度
    关于oracle with as用法
    SQL查询语句,怎样查询重复数据
    Axure RP Pro7.0的key注册码加汉化非破解
    秦曾昌人工智能课程---7、决策树集成学习Tree Ensembles
    秒懂机器学习---分类回归树CART
    秒懂机器学习---朴素贝叶斯
    秒懂机器学习---k临近算法(KNN)
    秒懂机器学习---机器学习无法逃避的梯度下降法
    秒懂机器学习---当机器学习遇上决策树....
  • 原文地址:https://www.cnblogs.com/CaptainSlow/p/9250970.html
Copyright © 2011-2022 走看看