1. 程式人生 > >[luogu] P4198 樓房重建

[luogu] P4198 樓房重建

思路 需要 沒有 span 修改 開始 什麽 src 無聊

題目描述

小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 樓房重建