1. 程式人生 > >談談今天寫線段樹時碰到的問題

談談今天寫線段樹時碰到的問題

問題 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;
 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值可能是非零的,甚至影響更新,導致錯誤。

總結

比賽時,這種問題非常難考慮到, 因為表面上看這樣寫確實是正確的。因此仔細考慮程序的每一個步驟。

談談今天寫線段樹時碰到的問題