P4198 樓房重建

2022-02-27 19:43:07 字數 1114 閱讀 6830

傳送門

很妙的思路

首先,我們可以把每一棟樓房轉化為它的頂部到原點這條直線的斜率,這樣就變成了從乙個序列中選出乙個最長上公升子串行(其實不是最長上公升子串行,不過可以這麼理解)

考慮用線段樹來維護,對於每個區間,我們維護這個區間的最大值以及這個區間的答案,那麼最後的答案就是\(ans[1]\)

對於葉節點來說,最大值就是它自己,答案為\(1\)

考慮怎麼合併區間。

首先左邊區間能看到的答案,當前區間必然也能看到

考慮右邊的區間。如果右區間的最大值小於等於左區間的最大值,那麼一定會被擋住啥都看不見

如果右區間的左區間的最大值小於等於左區間的最大值,左區間肯定會被擋住啥都看不見,那麼我們就遞迴進右區間的右區間繼續找答案

如果右區間的左區間的最大值大於左區間的最大值,那麼所有右區間的右區間裡所有原來能看到的現在還是能看到。而左區間裡繼續遞迴找

有點繞,建議看**理解比較好

總的複雜度為\(o(nlog^2n)\)

//minamoto

#include#define max(x,y) ((x)>(y)?(x):(y))

using namespace std;

#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?eof:*p1++)

char buf[1<<21],*p1=buf,*p2=buf;

int read()

char sr[1<<21],z[20];int c=-1,z=0;

inline void ot()

void print(int x)

const int n=1e5+5;

int n,m,ans[n<<2];double mx[n<<2];

#define ls (p<<1)

#define rs (p<<1|1)

int query(int p,int l,int r,double sl)

void upd(int p,int l,int r,int x,double sl)

int main()

return ot(),0;

}

P4198 樓房重建

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

P4198 樓房重建(思維)

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

P4198 樓房重建 線段樹

n nn條線,開始時第i ii條是 i,0 i,0 i,0 的乙個點。每次有操作把第x xx條線變成 x,0 x,0 x,0 到 x,y x,y x,y 然後求從 0,0 0,0 0,0 能看到幾條線。把線變成斜率的話就是對於每個點求乙個往後比它大的第乙個點然後一直跳來做了。線段樹的話主要是合併區間...