bzoj2957 樓房重建

2021-07-30 13:52:34 字數 1368 閱讀 4843

題目大意:

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

施工隊的建造總共進行了m天。初始時,所有樓房都還沒有開始建造,它們的高度均為0。在第i天,建築隊將會將橫座標為xi的房屋的高度變為yi(高度可以比原來大—修建,也可以比原來小—拆除,甚至可以保持不變—建築隊這天什麼事也沒做)。請你幫小a數數每天在建築隊完工之後,他能看到多少棟樓房?

題解:

線段樹

設mx[i]維護i這個點表示的區間中的最大斜率,ans[i]維護i這個點表示的區間中能被看到的樓房數。

改的話就直接單點修改。

對一段區間now來說,左半區間lc的ans是一定可以對它產生貢獻的。而右半區間的話,設左半區間的斜率的最大值為mv,遞迴進右半區間rc看比mv大的樓房個數。

同樣將右區間分成左子區間和右子區間。

如果mv≥mx[rc],即右半區間的最大值沒有左半區間的最大值大,那麼右半區間的所有樓房都不能被看到了,就return 0.

否則看左子區間的mx與mv的比較:

若mv≥mx[左子區間],那麼左子區間就沒有貢獻,就遞迴進右子區間看比mv大的個數。

若mx[左子區間]≥mv,那麼右子區間對區間now的貢獻跟它對右區間的貢獻是一樣的,因為左區間並沒有對它造成影響即ans[rc]-ans[左子區間]。然後就遞迴進左子區間看比mv大的個數。

然後就可以了。

#include

#include

#include

#include

#include

using namespace std;

#define maxn 400010

double mx[maxn];int ans[maxn];

double mymax(double x,double y)

int calc(int now,double mv,int l,int r)

void change(int now,int l,int r,int

x,double k)

int mid=(l+r)>>1,lc=now*2,rc=now*2+1;

if (x

<=mid) change(lc,l,mid,x,k);

else change(rc,mid+1,r,x,k);

ans[now]=ans[lc]+calc(rc,mx[lc],mid+1,r);

mx[now]=mymax(mx[lc],mx[rc]);

}int main()

return

0;}

bzoj 2957 樓房重建

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

BZOJ2957 樓房重建

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

BZOJ2957 樓房重建

題意 給定m m 100000 個操作,每次將座標軸上橫座標為x 1 x n 100000 的樓的高度設為y,之後回答在 0,0 能看到幾個樓。分析 7.19考試題,當時全場基本都寫得o nm 大暴力,gzz神犇用騙分法竟然ac了,但在bzoj上tle了,只能說考試時候資料水了。這題有兩種做法,一種...