洛谷 4198 樓房重建

2021-09-29 12:09:20 字數 1919 閱讀 6101

傳送門

在乙個二維平面上有 n

nn 棟樓房,第 i

ii 棟樓房可以用以 (i,

0)

(i,0)

(i,0

) 和 (i,

hi

)(i,h_i)

(i,hi​

) 為端點的線段表示,一開始所有的 hi=

0h_i=0

hi​=0。

有 m

mm 次操作,每次可以修改乙個 h

ih_i

hi​,並且在每次修改之後查詢在 (0,

0)

(0,0)

(0,0

) 能看到的樓房個數(如果以 (i,

hi

)(i,h_i)

(i,hi​

) 和 (0,

0)

(0,0)

(0,0

) 為端點的線段與其它樓房沒有交點,那麼 i

ii 就可見)。

資料範圍:n,m

≤105

n,m\le10^5

n,m≤10

5。可以先算一下 (i,

hi

)(i,h_i)

(i,hi​

) 與 (0,

0)

(0,0)

(0,0

) 的直線的斜率,能看到樓房的斜率一定是遞增的。

考慮用線段樹來維護這個東西,那麼關鍵就在於 pushup 操作了。

首先,左兒子的答案是可以直接加進來的,而右兒子會受到左兒子中最大值的限制。

具體來說,我們可以找到右兒子中第乙個比左兒子的 mxmx

mx大的位置,它的左邊都不能選,右邊按照原來的計算即可。

一邊找一邊算答案即可。

由於 pushup 是 o

(log⁡n

)o(\log n)

o(logn

) 的,所以總時間複雜度 o(n

log⁡2n

)o(n\log^2n)

o(nlog2n

)。

#include

using

namespace std;

namespace io

template

<

typename t>

inline t read()

inline

intin()

}using io::in;

const

int n=

1e5+5;

int n,m,sum[n<<2]

;double mx[n<<2]

;#define mid ((l+r)>>1)

intfind

(double num,

int root,

int l,

int r)

void

pushup

(int root,

int l,

int r)

void

modify

(int root,

int l,

int r,

int pos,

double k)

if(pos<=mid)

modify

(root<<

1,l,mid,pos,k)

;else

modify

(root<<1|

1,mid+

1,r,pos,k)

;pushup

(root,l,r);}

#undef mid

intmain()

return0;

}

洛谷P4198 樓房重建

題意 給定序列,每次修改乙個值,求字首最大值的個數。解 線段樹經典應用。每個節點維護最大值和該區間字首最大值個數。發現我們不用下傳標記,只需要合併區間。需要實現乙個函式int ask l r lm 求出區間 l r 中前乙個數是lm時字首最大值個數。那麼當lm large ls 時,return a...

洛谷 P4198 樓房重建

區間最大可修改上公升 線段樹做法,可以分塊亂搞 這道題只是詢問1到n區間,其實可以改成任意區間的最大上公升。首先注意題目是連線,因此不是高度上公升是斜率上公升 y x 但在之後的說明中都會說斜率為高度,大家把他想象成在樓底向上仰望看到多少棟樓。然後造樹,維護h,區間內最大的高度維護 s,區間內的最大...

洛谷P4198 樓房重建 分塊

小a的樓房外有一大片施工工地,工地上有n棟待建的樓房。每天,這片工地上的房子拆了又建 建了又拆。他經常無聊地看著窗外發呆,數自己能夠看到多少棟房子。為了簡化問題,我們考慮這些事件發生在乙個二維平面上。小a在平面上 0,0 點的位置,第i棟樓房可以用一條連線 i,0 和 i,hi 的線段表示,其中hi...