傳送門
在乙個二維平面上有 n
nn 棟樓房,第 i
ii 棟樓房可以用以 (i,
0)
(i,0)
(i,0
) 和 (i,
hi
)(i,h_i)
(i,hi
) 為端點的線段表示,一開始所有的 hi=
0h_i=0
hi=0。
有 m
mm 次操作,每次可以修改乙個 h
ih_i
hi,並且在每次修改之後查詢在 (0,
0)
(0,0)
(0,0
) 能看到的樓房個數(如果以 (i,
hi
)(i,h_i)
(i,hi
) 和 (0,
0)
(0,0)
(0,0
) 為端點的線段與其它樓房沒有交點,那麼 i
ii 就可見)。
資料範圍:n,m
≤105
n,m\le10^5
n,m≤10
5。可以先算一下 (i,
hi
)(i,h_i)
(i,hi
) 與 (0,
0)
(0,0)
(0,0
) 的直線的斜率,能看到樓房的斜率一定是遞增的。
考慮用線段樹來維護這個東西,那麼關鍵就在於 pushup 操作了。
首先,左兒子的答案是可以直接加進來的,而右兒子會受到左兒子中最大值的限制。
具體來說,我們可以找到右兒子中第乙個比左兒子的 mxmx
mx大的位置,它的左邊都不能選,右邊按照原來的計算即可。
一邊找一邊算答案即可。
由於 pushup 是 o
(logn
)o(\log n)
o(logn
) 的,所以總時間複雜度 o(n
log2n
)o(n\log^2n)
o(nlog2n
)。
#include
using
namespace std;
namespace io
template
<
typename t>
inline t read()
inline
intin()
}using io::in;
const
int n=
1e5+5;
int n,m,sum[n<<2]
;double mx[n<<2]
;#define mid ((l+r)>>1)
intfind
(double num,
int root,
int l,
int r)
void
pushup
(int root,
int l,
int r)
void
modify
(int root,
int l,
int r,
int pos,
double k)
if(pos<=mid)
modify
(root<<
1,l,mid,pos,k)
;else
modify
(root<<1|
1,mid+
1,r,pos,k)
;pushup
(root,l,r);}
#undef mid
intmain()
return0;
}
洛谷P4198 樓房重建
題意 給定序列,每次修改乙個值,求字首最大值的個數。解 線段樹經典應用。每個節點維護最大值和該區間字首最大值個數。發現我們不用下傳標記,只需要合併區間。需要實現乙個函式int ask l r lm 求出區間 l r 中前乙個數是lm時字首最大值個數。那麼當lm large ls 時,return a...
洛谷 P4198 樓房重建
區間最大可修改上公升 線段樹做法,可以分塊亂搞 這道題只是詢問1到n區間,其實可以改成任意區間的最大上公升。首先注意題目是連線,因此不是高度上公升是斜率上公升 y x 但在之後的說明中都會說斜率為高度,大家把他想象成在樓底向上仰望看到多少棟樓。然後造樹,維護h,區間內最大的高度維護 s,區間內的最大...
洛谷P4198 樓房重建 分塊
小a的樓房外有一大片施工工地,工地上有n棟待建的樓房。每天,這片工地上的房子拆了又建 建了又拆。他經常無聊地看著窗外發呆,數自己能夠看到多少棟房子。為了簡化問題,我們考慮這些事件發生在乙個二維平面上。小a在平面上 0,0 點的位置,第i棟樓房可以用一條連線 i,0 和 i,hi 的線段表示,其中hi...