日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

树状数组区间更新

發布時間:2025/3/21 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 树状数组区间更新 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

?

樹狀數組區間更新

?

在今天的文章開始之前,給大家提一個建議,由于線段樹和樹狀數組這兩個結構的分析有很多聯系,因此,建議沒有看前幾篇文章的朋友一定需要了解一下前面的內容。鏈接如下:

線段樹+RMQ問題第二彈

線段樹第二彈(區間更新)

樹狀數組(Binary Indexed Tree,BIT)

?

上篇文章我們討論了樹狀數組的基本結構以及它最擅長的兩個功能:單點更新和區間求和,今天,我們來接著上一篇文章的內容繼續深入研究。上篇文章我們是將樹狀數組和線段樹進行對比講解的,既然線段樹的章節我們介紹了區間求和、區間最值、單點更新、區間更新,那么對應的,樹狀數組也應該有個區間更新吧。但我們從上篇文章中的分析可以看出來,樹狀數組確實不擅長區間更新,它也無法進行區間更新,這是不是就意味著文章寫到這里就結束了呢?當然不是,作為一個求真務實從不坑蒙拐騙的誠信公眾號,我當然不會做出那種用標題騙閱讀量的事情。那之前說的樹狀數組不會、不能進行區間更新是怎么回事?答案就是樹狀數組可以利用某些手段(比如單點更新)來達到區間更新的目的,讓結果和區間更新后的結果相吻合,看似實現了區間更新,實際是偽區間更新。所以,坑蒙拐騙的是它,可不是我。沒有看過上篇文章的建議先看上篇文章(樹狀數組(Binary Indexed Tree,BIT))了解基礎知識,便于更好的理解本篇文章。

既然它是可以實現偽區間更新的,我們做題的時候又只是追求輸出結果的正確,不妨就花幾分鐘看一看到底它是怎么實現的?

?

在此我們稱事先給定的數組為原數據數組,按照樹狀數組結構實現的數組稱為樹狀數組,本篇文章中討論的區間更新方式是給原數據數組一段區間的所有元素加上一個數值 a 。

從上篇文章中我們可以知道,樹狀數組的區間求和實際是通過區間兩端點的前綴和相減實現的,檢驗區間更新是否正確的方式便是區間求和,既然區間求和只需要保證區間兩端點的正確性,就給我們留出了可乘之機,我們可以在進行區間更新的時候只對兩端點進行更新操作,保證數值正確即可。現在,我們就需要對更新后整個樹狀數組的特征進行觀察,找出規律。

假設某次給原數據數組區間 i ~j 上的所有元素均加 a,此時若要查詢某一區間 p~q 的元素和,會是怎樣的結果呢?我們首先應該分別求解 p 和 q 位置的前綴和,p 和 q 求前綴和的方法是一樣的,所以我們研究的問題變成了區間更新和單點查詢,那么一般的我們假設求 x 的前綴和,如下圖所示:

上圖中, i~j 表示區間更新的范圍,x 表示待求前綴和的結束元素位置, sum[x]表示區間更新前 x 位置的前綴和,a 表示區間更新過程中對每個元素增加的值,縱坐標 y 表示區間更新后相應的前綴和的增加量,即 y(x)+sum[x] 的值為區間更新后x位置的前綴和。由圖可知,

在 x<i 時,y 的值恒為 0

在i <= x <= j 時,y的值隨著 x 的增加而遞增

在 x > j 時,y的值恒為 (j - i +1) * a

?

我們知道,在單點更新的時候,對一個位置 x 的值加 a 時,位置在 x 之前的所有前綴和都是沒有影響的,受影響的是從 x 開始之后的所有位置的前綴和。

知道了這些之后,我們就可以利用上篇文章中實現的單點更新和區間查詢進行區間更新和單點查詢了,由上圖可知,在 x < i 和 x > j 的范圍內(待更新區間之外),只要區間更新的加數 a 確定,這些前綴和便是固定值,不需要知道單點查詢時候的位置,因此這部分工作可以在更新的時候實現,具體如何實現呢?

觀察上圖,我們發現 在i <= x <= j 時,前綴和增量 y = (x-i+1)*a = x*a -(i-1)*a ;在 x > j 時,前綴和增量 y = (j - i +1 )*a = j*a - (i-1)*a ?; 由此可以得出結論,在 x >= i 時,y 的表達式中均包含 -(i-1)*a ,所以根據前綴和的規律,我們利用單點更新將此值加在 i 位置的前綴和上,則可以達到給 x >= i 范圍內的所有前綴和均加上了此值。在 ?i <= x <= j 的區間范圍內,我們發現前綴和增量表達式 y 除 -(i-1)*a 這部分外,剩余的部分為 x*a ,x 即為單點查詢的位置,這個值不確定,只有在某一次查詢的時候才能被確定,因此,這個操作需要在單點查詢的時候完成。在 x > j 的范圍內,前綴和表達式 y = j*a - (i-1)*a ?, 除已經在 x = i 的位置處理的 -(i-1)*a 這部分之外,剩余部分為 j*a ?,這部分值只與區間更新的端點和更新的加數 a 有關,因此可以在更新時候處理,這時候我們需要將 j+1 位置的前綴和由 sum[ j+1 ] 更新為 ?sum[ j+1] + j*a 。至此,除了查詢 i <= x <= j 范圍的值不正確之外,其余值都能夠保證正確性。

當單點查詢的位置 x 在 i~j 范圍內的時候,我們需要在 x 的位置 單點更新前綴和 sum[ x ] 為 ?sum[x] +x*a 。現在,我們已經將三個區間都處理結束了,對嗎?但是,這是真的結束嗎? 大家是否還記得單點更新的操作?操作是這樣的:在單點更新的時候,對一個位置 x 的值加 a 時,位置在 x 之前的所有前綴和都是沒有影響的,受影響的是從 x 開始之后的所有位置的前綴和。這也就意味著當單點查詢的位置 x 在 i~j 范圍內的時候,我們對 x 位置的單點更新實際上已經影響到了我們在區間更新時候已經處理好的區間 ?x > j ,因此我們需要將此處因單點更新加的值 x*a 減去。這也就意味著,我們需要將加數 a 存儲起來,否則,等到單點查詢的時候,加數 a 都已經變成若干次區間查詢后的加數了。但由于,同一個區間的加數多次疊加后,結果還是正確的。因此,我們可以仿照線段樹時的 lazy_tag 想法存儲每個節點對應的加數(線段樹 lazy_tag相關知識詳見:線段樹第二彈(區間更新))。

對于某一個具體的加數該如何存儲和維護呢?有了前面的分析思路,我們應該可以用兩個樹狀數組分別存儲前綴和與加數,其中一個樹狀數組 lazy_tag來存儲加數,假設某次區間更新的范圍為 i~j ,加數為 a ,我們需要做的操作為:?

lazy_tag[i] += a ; //給 x >= i 的所有節點加數均加 a

lazy_tag[j+1] -= a ; // 給 x >j 的所有節點均減 a ,消除 i 位置處理的影響

這樣,就能保證僅對 i ~j 范圍內的加數加了 a ,以此配合區間更新時的操作保證所有前綴和的正確性。此處,對加數的處理和原問題(區間更新)處理思路是一樣的,給某一區間的所有加數均加 a 的問題實質就是區間更新的問題。因此此處,某一位置 x 的加數不是 lazy_tag[x] 的值,而是 lazy_tag 樹狀數組的第 x 位置前綴和。

此時,原數據的前綴和與加數的分布為:

?

理論知識如上,接下來,我將為大家展示代碼實現部分,希望可以幫助大家理解本篇文章。如下所示:

?

今天的分享到此結束,大家如果發現文章中寫的不合理的地方,歡迎在下方留言區留言,不勝感激。

?

?

沒有關注公眾號的朋友可以長按下圖識別二維碼關注公眾號了解最新文章。

?

?


?

轉載于:https://www.cnblogs.com/detrol/p/7586083.html

總結

以上是生活随笔為你收集整理的树状数组区间更新的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。