題意:給定序列,每次修改乙個值,求字首最大值的個數。
解:線段樹經典應用。
每個節點維護最大值和該區間字首最大值個數。
發現我們不用下傳標記,只需要合併區間。
需要實現乙個函式int ask([l r] lm)求出區間[l r]中前乙個數是lm時字首最大值個數。
那麼當lm >= large[ls]時,return ask([mid r] lm)
這個很好理解,左子區間的所有數都不會成為字首最大值。
當lm < large[ls]時,return ask([l mid] lm) + (sum[o] - sum[ls])
這個注意,不是sum[rs]因為sum[rs]的意義是從0開始,而這個的前面會有large[ls]擋著,所以是sum[o] - sum[ls]
修改的時候先一路到底把large值改了。然後return的時候把沿途區間都更新。
具體來說就是sum[o] = ask([l r] 0)...等等,好像有問題。
lm < large[ls]的時候,求值是要呼叫sum[o]的,這不就迴圈呼叫導致出錯了嗎?
所以寫成sum[o] = sum[ls] + ask([mid r] large[ls])即可。
本題不用建樹。需要建樹的時候就跟修改類似的寫法即可。
1 #include 2 #include 3ac**4const
int n = 100010;5
6double a[n], large[n << 2];7
int n, sum[n << 2];8
9int ask(int l, int r, int o, double
lm)
13int mid = (l + r) >> 1;14
if(lm > large[o << 1
]) 17
else20}
2122
void change(int p, double v, int l, int r, int
o) 28
int mid = (l + r) >> 1;29
if(p <=mid)
32else
35 large[o] = std::max(large[o << 1], large[o << 1 | 1
]);36 sum[o] = sum[o << 1] + ask(mid + 1, r, o << 1 | 1, large[o << 1
]);37
return;38
}3940int
main()
4950
return0;
51 }
洛谷 P4198 樓房重建
區間最大可修改上公升 線段樹做法,可以分塊亂搞 這道題只是詢問1到n區間,其實可以改成任意區間的最大上公升。首先注意題目是連線,因此不是高度上公升是斜率上公升 y x 但在之後的說明中都會說斜率為高度,大家把他想象成在樓底向上仰望看到多少棟樓。然後造樹,維護h,區間內最大的高度維護 s,區間內的最大...
洛谷P4198 樓房重建 分塊
小a的樓房外有一大片施工工地,工地上有n棟待建的樓房。每天,這片工地上的房子拆了又建 建了又拆。他經常無聊地看著窗外發呆,數自己能夠看到多少棟房子。為了簡化問題,我們考慮這些事件發生在乙個二維平面上。小a在平面上 0,0 點的位置,第i棟樓房可以用一條連線 i,0 和 i,hi 的線段表示,其中hi...
洛谷 P4198 樓房重建 題解
題面 首先你要知道題問的是什麼 使用一種資料結構,動態地維護以1為起點地最長上公升子串行 把樓房的高度轉化成斜率地序列 的長度 怎麼做?線段樹!初始化 對於每乙個葉子節點,從這段區間頭可以看到的樓房數量一定為1,區間斜率最大值一定為該點的斜率 在合併時 1.我們可以先查詢右區間的左區間的最大值,如果...