bzoj2957 樓房重建 線段樹

2021-08-14 14:14:09 字數 1037 閱讀 5646

解題思路:

題意即是要動態維護斜率的最長上公升子串行。

考慮線段樹,對於線段樹每個結點維護兩個值:ans和maxl,ans表示只考慮這個區間的可視區間的答案,maxl表示這個區間的最大斜率。

那麼問題的關鍵就在於修改後如何合併兩個區間(update),顯然左區間的答案肯定可以作為總區間的答案的一部分,那麼接下來就是看右區間有多少個在新加入左區間的約束後(即是maxl[k<<1])是可行的。

(注意文中左區間、左子區間……的區別)

考慮如果右區間最大值都小於等於左區間最大值那麼右區間就沒有貢獻了,相當於是被整個擋住了。如果大於最大值,就再考慮右區間的兩個子區間:左子區間、右子區間。如果左子區間的最大值小於等於左區間最大值,那麼就遞迴處理右子區間;否則就遞迴處理左子區間,然後加上右子區間原本的答案。考慮這樣做的必然性:因為左區間最高的比左子區間最高的矮,那麼相當於是左區間對於右子區間沒有約束,都是左子區間產生的約束。但是右子區間的答案要用右區間答案-左子區間答案,不能直接呼叫右子區間本身答案,因為其本身答案沒有考慮左子區間的約束。

#include

using

namespace

std;

int getint()

const

int n=100005;

int n,m,cnt[n<<2];

double mx[n<<2];

int calc(int k,int l,int r,double v)

void modify(int k,int l,int r,int p,double v)

int mid=l+r>>1;

if(p<=mid)modify(k<<1,l,mid,p,v);

else modify(k<<1|1,mid+1,r,p,v);

mx[k]=max(mx[k<<1],mx[k<<1|1]);

cnt[k]=cnt[k<<1]+calc(k<<1|1,mid+1,r,mx[k<<1]);

}int main()

return

0;}

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...