題目大意:
小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了,只能說考試時候資料水了。這題有兩種做法,一種...