Luogu 4198 樓房重建

2022-06-13 02:39:08 字數 1170 閱讀 3955

bzoj 2957

挺妙的題。

先把題目中的要求轉化為斜率,乙個點$(x, y)$可以看成$\frac$,這樣子我們要求的就變成了乙個區間內一定包含第乙個值的最長上公升序列。

然後把這個序列開成線段樹,維護一下區間內的答案$res$和最大值$mx$,顯然對於葉子結點有$mx = a_l$,$res = 1$。

$mx$的更新非常簡單直接取個最大值就好了,但是$res$的更新有一些複雜,對於乙個區間$[l, r]$,左兒子$[l, mid]$的值可以直接加過來,因為左兒子一定會被選到,但是右兒子的值並不那麼容易計算,我們用$solve(l, r, v)$表示區間$[l, r]$內第乙個值超過$v$的元素必選的最長上公升序列的大小,當$l == r$的時候,只要觀察$mx$是否大於$v$就可以得到答案,而$solve$函式的合併則與左兒子區間的最大值有關,具體來說:當$mx_ > v$的時候,右兒子全部被選到,然後遞迴計算左兒子$solve(l, mid, v)$,否則遞迴計算右兒子。

一次合併需要訪問$log$個結點,總時間複雜度$o(nlog^2n)$。

code:

#include #include 

using

namespace

std;

typedef

double

db;const

int n = 1e5 + 5

;int

n, qn;

inline

void read(int &x)

inline db max(db x, db y)

namespace

segt

void modify(int p, int l, int r, int

x, db v)

if(x <=mid) modify(lc, l, mid, x, v);

else modify(rc, mid + 1

, r, x, v);

mx[p] =max(mx[lc], mx[rc]);

res[p] = res[lc] + solve(rc, mid + 1

, r, mx[lc]);

}} using

namespace

segt;

intmain()

return0;

}

view code

Luogu4198 樓房重建

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

Luogu4198 樓房重建

帶修改的區間維護最大斜率。題面用線段樹區間維護斜率。考慮如何向上合併。左半段一定有貢獻。如果左半段的最大斜率大於右半段,右半段無貢獻。否則,如果在右半段中,左邊大於左半段,則直接加上右邊符合條件的 總 左,因為右邊現有的是大於左邊的 遞迴考慮左邊 否則,遞迴右邊。這個玩意好像不能自然想出來。incl...

洛谷 4198 樓房重建

傳送門 在乙個二維平面上有 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 ...