線段樹 思維題 樓房重建

2021-09-24 09:56:12 字數 1532 閱讀 8690

小a的樓房外有一大片施工工地,工地上有n棟待建的樓房。

每天,這片工地上的房子拆了又建、建了又拆。他經常無聊地看著窗外發呆,數自己能夠看到多少棟房子。

為了簡化問題,我們考慮這些事件發生在乙個二維平面上。

小a在平面上(0,0)點的位置,第i棟樓房可以用一條連線(i,0)和(i,hi)的線段表示,其中hi為第i棟樓房的高度。如果這棟樓房上任何乙個高度大於0的點與(0,0)的連線沒有與之前的線段相交,那麼這棟樓房就被認為是可見的。

施工隊的建造總共進行了m天。 初始時,所有樓房都還沒有開始建造,它們的高度均為0。

在第i天,建築隊將會將橫座標為xi的房屋的高度變為yi(高度可以比原來大—修建,也可以比原來小—拆除,甚至可以保持不變—建築隊這天什麼事也沒做)。請你幫小a數數每天在建築隊完工之後,他能看到多少棟樓房?

首先,乙個房子要被看到,必須滿足它前面的房子中不存在斜率比它大的。

顯然,乙個區間的答案=左區間答案+右區間受左區間的最大高度影響後的答案

最大高度顯然可以用線段樹來維護,關鍵是如何求解受某乙個高度影響後的答案,我們單獨解決。

問題:求解當前區間受高度v影響後的答案是什麼。

由於遞迴套遞迴,時間複雜度:o(n

log2

n)

o(n log^2 n)

o(nlog

2n)

**如下:

#include

using

namespace std;

const

int n =

200000

;int n, m;

struct segment a[n*4]

;inline

intread

(void

)void

build

(int p,

int l,

int r)

intinflu

(double v,

int p)

//求解區間受高度v影響後的答案

void

change

(int p,

int x,

double v)

int mid = a[p]

.l+a[p]

.r>>1;

if(x <= mid)

change

(p*2

,x,v);if

(x > mid)

change

(p*2+1

,x,v)

; a[p]

.max =

max(a[p*2]

.max,a[p*2+

1].max)

; a[p]

.ans = a[p*2]

.ans+

influ

(a[p*2]

.max,p*2+

1);return;}

intmain

(void

)return0;

}

樓房重建 (線段樹)

2957 樓房重建 time limit 10 sec memory limit 256 mb submit 2289 solved 1081 submit status discuss description 小a的樓房外有一大片施工工地,工地上有n棟待建的樓房。每天,這片工地上的房子拆了又建 建...

bzoj2957 線段樹 樓房重建

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

BZOJ2957 樓房重建(線段樹)

這裡放傳送門 可以發現如果一段樓房能被看見,那麼它們跟原點的連線的斜率都是單調遞增的。於是這就變成了乙個維護上公升序列的題。這裡的上公升序列不是最長上公升子串行那樣的東西,而是相當於貪心地選擇,選中的子串行中的每乙個元素它前面都不能存在大於等於它的元素。比如說,有乙個斜率序列是1,2,4,3,4,如...