BZOJ2957 樓房重建 線段樹

2021-08-14 13:39:46 字數 1179 閱讀 4388

題意:

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

為了簡化問題,我們考慮這些事件發生在乙個二維平面上。小a在平面上(0,0)點的位置,第i棟樓房可以用一條連線(i,0)和(i,hi)的線段表示,其中hi為第i棟樓房的高度。如果這棟樓房上任何乙個高度大於0的點與(0,0)的連線沒有與之前的線段相交,那麼這棟樓房就被認為是可見的。

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

solution:

思路借鑑黃學長。

此題有兩種做法:分塊和線段樹,這裡介紹一種線段樹的解法:

我們修改乙個數隻會影響這個數後面的數,我們考慮線段樹劃分出的線段,會產生兩種情況:

1. 線段中的最大值小於等於修改的數,那麼這個線段的貢獻為0

2. 線段中的最大值大於修改的數,如果左側的最大值大於修改的數,那麼右側不受影響,遞迴處理左側即可,否則就變成了情況1

看起來難以實現,實際上理解演算法後非常好寫

**:

#include

#include

using namespace std;

int n,m;

struct treetr[4

*100010];

intx,y;

void build(int i,int l,int r)

int calc(int i,double val)

void modify(int i,int

pos,double val)

int mid=l+r>>1;

if (pos

<=mid) modify(i<<1,pos,val);

else modify(i<<1|1,pos,val);

tr[i].maxn=max(tr[i<<1].maxn,tr[i<<1|1].maxn);

tr[i].ans=tr[i<<1].ans+calc(i<<1|1,tr[i<<1].maxn);

}int main()

}

BZOJ2957 樓房重建(線段樹)

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

BZOJ2957 樓房重建 線段樹

題目 time limit 10 sec memory limit 256 mb submit 2259 solved 1069 submit status discuss 小a的樓房外有一大片施工工地,工地上有n棟待建的樓房。每天,這片工地上的房子拆了又建 建了又拆。他經常無聊地看著窗外發呆,數自...

bzoj2957樓房重建 線段樹

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