洛谷傳送門
jdoj傳送門
小新經常陪小白去公園玩,也就是所謂的遛狗啦…在小新家附近有一條「公園路」,路的一邊從南到北依次排著n個公園,小白早就看花了眼,自己也不清楚該去哪些公園玩了。 一開始,小白就根據公園的風景給每個公園打了分。小新為了省事,每次遛狗的時候都會事先規定乙個範圍,小白只可以選擇第a個和第b個公園之間(包括a、b兩個公園)選擇連續的一些公園玩。小白當然希望選出的公園的分數總和盡量高咯。同時,由於一些公園的景觀會有所改變,所以,小白的打分也可能會有一些變化。 那麼,就請你來幫小白選擇公園吧。
第一行,兩個整數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的整數。
小白每出去玩一次,都對應輸出一行,只包含乙個整數,表示小白可以選出的公園得分和的最大值。
5 3 1 2 -3 4 5 1 2 3 2 2 -1 1 2 3
2 -1
題面不難理解,就是簡單的動態單點修改+區間最大子段和。
但是如何維護區間最大子段和呢?dp?dp的複雜度是\(o(n)\)的,顯然不行,而且,dp也不支援動態的修改。
那麼我們當然要選擇區間問題的好幫手:區間樹了(線段樹的別名)。
當然,你得知道線段樹是什麼,如果不會請走這邊:
線段樹詳解
在鄙人的理解中,線段樹作為一種資料結構,其思想是分治的樹形dp。就拿最簡單的線段樹來講,動態修改+維護區間最大值。我們可以把線段樹的每個節點理解成樹形dp的狀態:表示當前節點維護的區間\([l,r]\)的最大值,那麼顯而易見,上層節點可以由它的兩個兒子推出,符合無後效性和最優子結構。那麼這就是乙個樹形dp嘛!
那為什麼又有分治思想呢?因為當前節點維護的區間是二分的,這就是一種分而治之的思想。
那麼,除了線段樹支援的基本三大操作:求和、求最大/最小值之外,其他的區間維護問題就也可以使用線段樹解決。運用的還是分治+樹形dp的思想。即只需要考慮這麼乙個問題:如何設定狀態才能使得線段樹父子節點之間可以上推。
回到這個問題。動態修改+區間最大子段和。最大子段和怎麼維護呀?首先,我想到就粗暴地設定狀態為:」\(tree[pos]\)表示本區間的最大子段和。「但是顯然的是,這種狀態是不支援上推的,它的正確性無法保證,因為可能會有最大子段和是跨過這個區間的中點的,所以不能以中點分成兩個兒子來推。
怎麼辦呢?我們需要合理地設定乙個或多個狀態,使得這些狀態的父子關係可以平滑向上更新。
那麼我們考慮這麼設:
設定:\(tree[pos]\)表示當前節點表示區間的最大子段和
\(lmax[pos]\)表示當前節點表示區間一定包含左端點的最大子段和
\(rmax[pos]\)表示當前節點表示區間一定包含右端點的最大子段和
\(sum[pos]\)表示當前節點表示區間的總和
為什麼這麼設定呢?仍然回到上面講到的問題:為什麼不能只設\(tree[pos]\)表示答案呢?因為可能存在最大子段和的區間橫跨中點的情況出現。那麼如何才能把這種情況也包含進去呢?簡單啊,把這個區間拆開就好了,於是就有了以上\(lmax,rmax\)的狀態。
於是,我們可以平滑的轉移:
設\(lson/rson\)為當前節點\(pos\)的左右兒子,有:
\(tree[pos]=\max(tree[lson],tree[rson],lmax[rson]+rmax[lson])\)
然後我們還需要考慮如何維護\(lmax,rmax\),也很簡單:
\(lmax[pos]=\max(sum[lson]+lmax[rson],lmax[lson])\)
\(rmax[pos]=\max(rmax[rson],rmax[lson]+sum[rson])\)
問題解決:
**:
#include#include#define lson pos<<1
#define rson pos<<1|1
using namespace std;
const int maxn=5*1e5+10;
int n,m;
int w[maxn];
struct node
a[maxn<<2];
void pushup(int pos)
void build(int pos,int l,int r)
build(lson,l,mid);
build(rson,mid+1,r);
pushup(pos);
}void update(int pos,int l,int r,int x,int k)
if(x<=mid)
update(lson,l,mid,x,k);
else
update(rson,mid+1,r,x,k);
pushup(pos);
}node query(int pos,int l,int r,int x,int y)
return ret;
}int main()
else
update(1,1,n,x,y);
}return 0;
}
vijos P1083 小白逛公園
小新經常陪小白去公園玩,也就是所謂的遛狗啦 在小新家附近有一條 公園路 路的一邊從南到北依次排著n個公園,小白早就看花了眼,自己也不清楚該去哪些公園玩了。一開始,小白就根據公園的風景給每個公園打了分 小新為了省事,每次遛狗的時候都會事先規定乙個範圍,小白只可以選擇第a個和第b個公園之間 包括a b兩...
vijos P1083 小白逛公園
演算法 線段樹 題解 學自 的回答 回溯時維護一段區間的以下域 以上域在葉子節點中的值,都等於節點代表公園的評分 設當前節點為 x,左孩子為 l,右孩子為 r。則 x.suml max l.suml,l.sum r.suml x.sumr max r.sumr,r.sum l.sumr x.sum ...
Vijos1083 小白逛公園
description 小新經常陪小白去公園玩,也就是所謂的遛狗啦 在小新家附近有一條 公園路 路的一邊從南到北依次排著n 個公園,小白早就看花了眼,自己也不清楚該去哪些公園玩了。一開始,小白就根據公園的風景給每個公園打了分 小新為了省事,每次遛狗的時候都會事先規定乙個範圍,小白只可以選擇第a個和第...