談談今天寫線段樹時碰到的問題
阿新 • • 發佈:2018-07-01
問題 size 區間最值 void span 正是 tmp 不同 定義
今天打一個線段樹,求區間最值的。
它有一個這樣的更新函數定義:
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; 9pushdown(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(intrt, 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值可能是非零的,甚至影響更新,導致錯誤。
總結
比賽時,這種問題非常難考慮到, 因為表面上看這樣寫確實是正確的。因此仔細考慮程序的每一個步驟。
談談今天寫線段樹時碰到的問題