[luogu] P4198 樓房重建
題目描述
小A的樓房外有一大片施工工地,工地上有N棟待建的樓房。每天,這片工地上的房子拆了又建、建了又拆。他經常無聊地看著窗外發呆,數自己能夠看到多少棟房子。
為了簡化問題,我們考慮這些事件發生在一個二維平面上。小A在平面上(0,0)點的位置,第i棟樓房可以用一條連接(i,0)和(i,Hi)的線段表示,其中Hi為第i棟樓房的高度。如果這棟樓房上任何一個高度大於0的點與(0,0)的連線沒有與之前的線段相交,那麽這棟樓房就被認為是可見的。
施工隊的建造總共進行了M天。初始時,所有樓房都還沒有開始建造,它們的高度均為0。在第i天,建築隊將會將橫坐標為Xi的房屋的高度變為Yi(高度可以比原來大—修建,也可以比原來小—拆除,甚至可以保持不變—建築隊這天什麽事也沒做)。請你幫小A數數每天在建築隊完工之後,他能看到多少棟樓房?
輸入輸出格式
輸入格式:
第一行兩個正整數N,M
接下來M行,每行兩個正整數Xi,Yi
輸出格式:
M行,第i行一個整數表示第i天過後小A能看到的樓房有多少棟
輸入輸出樣例
輸入樣例#1:
3 4
2 4
3 6
1 1000000000
1 1
輸出樣例#1:
1
1
1
2
說明
對於所有的數據1<=Xi<=N,1<=Yi<=10^9
N,M<=100000
解題思路
首先看題面,對於每個位置,能不能被看到只取決於這個位置上樓的高度。換言之,取決於斜率k,(y = k x + b)。
暴力思路
求出每個點的斜率,然後循環掃一遍。
int max_k = -INF;for(int i = 1; i <= n; i++) { if(k[i] > max_k) { max_k = k[i]; ans++; } }
加上內存優化後實測50分。
優化
在暴力思路中,我們每次在找的只是最值。
根據公式:
區間 + 最值 = 線段樹
可以考慮使用線段樹優化。
具體辦法是:
利用線段樹維護每個區間的最大斜率以及能被看見的個數。
假設修改在圖中紅點處,那麽綠色區能被看見的樓房不受影響,不需要改變。
對於藍色區,如果最大斜率小於紅點處的斜率,就全部去死吧把這個區間的能被看到的樓房數修改成0。else,往下遞歸。
重復執行:如果區間最大斜率小於紅點斜率,區間數量就改成0,不然就接著遞歸,最後留下的就是能被看見的。
這樣就可以水進時限了
[luogu] P4198 樓房重建