JDOJ-P1260 VIJOS-P1083 小白逛公園
首先,在這裏給大家推薦一個網站,https://neooj.com:8082,這是我母校的網站
言歸正傳,題目描述
VIJOS-P1083 小白逛公園
Time Limit: 1 Sec Memory Limit: 128 MB
Description
小新經常陪小白去公園玩,也就是所謂的遛狗啦…在小新家附近有一條“公園路”,路的一邊從南到北依次排著n個公園,小白早就看花了眼,自己也不清楚該去哪些公園玩了。一開始,小白就根據公園的風景給每個公園打了分。小新為了省事,每次遛狗的時候都會事先規定一個範圍,小白只可以選擇第a個和第b個公園之間(包括a、b兩個公園)選擇連續的一些公園玩。小白當然希望選出的公園的分數總和盡量高咯。同時,由於一些公園的景觀會有所改變,所以,小白的打分也可能會有一些變化。 那麽,就請你來幫小白選擇公園吧。
Input
第一行,兩個整數N和M,分別表示表示公園的數量和操作(遛狗或者改變打分)總數。接下來N行,每行一個整數,依次給出小白 開始時對公園的打分。接下來M行,每行三個整數。第一個整數K,1或2。K=1表示,小新要帶小白出去玩,接下來的兩個整數a和b給出了選擇公園的範圍(1≤a,b≤N);K=2表示,小白改變了對某個公園的打分,接下來的兩個整數p和s,表示小白對第p個公園的打分變成了s(1≤p≤N)。其中,1≤N≤500 000,1≤M≤100 000,所有打分都是絕對值不超過1000的整數。
Output
小白每出去玩一次,都對應輸出一行,只包含一個整數,表示小白可以選出的公園得分和的最大值。
Sample Input
5 3 1 2 -3 4 5 1 2 3 2 2 -1 1 2 3
Sample Output
2 -1
思路
註:以下寫的i代表的是一個左兒子的編號,i+1代表的是一個右兒子的編號,new代表的是他倆的父親
對於這道題目,是區間查詢單點修改。又由於數據範圍比較大,所以很容易分析出來用線段樹進行維護。
再分析應該怎麽維護每一個區間,這道題應該維護四個狀態,區間和sumi,從左開始最大連續和lefti,從右開始最大連續和righti,以及在這個區間中最大連續和maxi,具體如左圖所示
對於建樹,難的是怎麽可以合並這些節點,如右圖所示,每兩個節點就可以這樣合並,首先解釋一下如何合並出來新的節點的左邊連續最大和,可以看出,左面的和(sumi)加上右面的最大左邊連續和(left(i+1)),也就是new_left1,但是這只是一種可能,還有一種可能是就是左邊節點的左邊最大連續和,這兩個值取max,left(new)=max(new_left1,lefti);同樣右邊也是這樣求,right(new)=max(new_right1,righti);求和好求,直接加就好啦,sum(new)=sumi+sum(i+1);求max就不太好求了,由於左兒子的右邊最大和右兒子的左邊最大可以合並,所以我又開了一個new_max1,max(new)=max(new_max1,maxi,max(i+1))。
修改比較好修改,直接找到當前節點O(1)修改就好了,但要註意的是,修改過後我們需要重新維護一下當前點以及當前點以上與這個點有關的所有點,維護過程就是之前建樹的過程,時間復雜度O(n*log(n));查詢比較復雜,搜索區間和查詢區間有三種情況(如下圖)對於這三種情況進行以下討論,會輕松的發現,當find_r>mid=(dfs_l+dfs_r)>>1時,應該便利右兒子,同理當find_l<=mid=(dfs_l+dfs_r)>>1時,應該便利左兒子,當查詢區間完全包含搜索區間時,便沒有必要查詢,直接返回。當然本題是要查最大值,然而最大連續段有可能橫跨多個區間,所以可以在找到的小節點上再建一棵線段樹,最後直接輸出新線段樹的根節點信息就可以了,順便說一下新的節點的建樹和原本的建樹一樣。
具體實現下午發上來
JDOJ-P1260 VIJOS-P1083 小白逛公園