luogu題解P4198樓房重建 線段樹神操作

2022-03-13 05:22:31 字數 1266 閱讀 4424

一句話題意,一條數軸上有若干樓房,座標為\(xi\)的樓房有高度\(hi\),那麼它的斜率為\(hi/xi\),操作包含單元素高度修改,動態詢問最長上公升斜率序列個數

一開始想什麼分治或是離線操作之類的,卻因為水平低並不會做,看了題解居然發現就是線段樹!看了一下感覺真妙啊,線段樹真是個神奇的資料結構

線段樹維護兩個東西\(sum[now],mx[now]\);

\(sum[now]\)是\(now\)管轄區間\([l,r]\)的最長上公升斜率個數

類似的\(mx[now]\)就是那個區間最大斜率,也就是最長上公升序列中最右邊的

我們假設更新操作遞迴到\([l,r]\)區間,設\(p\)為\([l,mid]\)區間最大斜率

\(mx[now<<1]\)

那麼\([l,r]\)區間的貢獻\((sum[now])\)顯然等於\([l,mid]\)區間貢獻\((sum[now<<1])\)

\(+\) 統計\([mid+1,r]\)區間中大於\(p\)的最長上公升序列個數.

那麼怎麼計算\([mid+1,r]\)區間中的大於\(p\)的最長上公升序列個數呢,這個我在**中給出了詳細的注釋

#include #include #include #include #include #include #define ll long long 

#define ri register int

using std::min;

using std::max;

template inline void read(t &x)

const int maxn=100005;

const int inf=0x7fffffff;

int n,m,t;

double dta,p;

struct segment_tree

void update(int now,int l,int r)

int mid=(l+r)>>1;

if(t<=mid)update(now<<1,l,mid);

else update(now<<1|1,mid+1,r);

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

p=mx[now<<1];//左區間最大值

sum[now]=sum[now<<1]+calc(now<<1|1,mid+1,r);//計算右區間貢獻

return ;

}}t;

int main()

return 0;

}

P4198 樓房重建

傳送門 很妙的思路 首先,我們可以把每一棟樓房轉化為它的頂部到原點這條直線的斜率,這樣就變成了從乙個序列中選出乙個最長上公升子串行 其實不是最長上公升子串行,不過可以這麼理解 考慮用線段樹來維護,對於每個區間,我們維護這個區間的最大值以及這個區間的答案,那麼最後的答案就是 ans 1 對於葉節點來說...

P4198 樓房重建

題意 n 棟待建的樓房,站在 0,0 點,對於樓房 i 來說,如果從原點能看到樓房的樓頂且沒有樓房阻擋,就算能看到該樓房 每次對於一座樓房可以增加高度和減小高度,每次修改後問最多能看到多少棟樓房?題解 線段樹維護區間斜率最大值,以及區間最長上公升子串行 即斜率遞增 的長度,難點在於區間的合併 對於每...

P4198 樓房重建(思維)

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