清華集訓 2013 樓房重建(線段樹)

2021-08-22 13:16:37 字數 2409 閱讀 3669

題意轉化:動態維護乙個單調棧,支援單點修改,整體查詢單調棧長度。

使用線段樹。對於每個節點,維護 ma

x[ro

ot] max

[roo

t]

表示區間最大值,cn

t[ro

ot] cnt

[roo

t]

表示區間中的單調棧的長度。在自底向上 maintain 的時候,cn

t[ro

ot]=

cnt[

lson

]+ca

lc(r

son,

max[

lson

])c nt

[roo

t]=c

nt[l

son]

+cal

c(rs

on,m

ax[l

son]

),其中 ca

lc(r

oot,

valu

e)c al

c(ro

ot,v

alue

)表示只保留

>va

lue >va

lu

e的元素,ro

otr oo

t區間的單調棧長度。

我們考慮如何計算 ca

lcc al

c。當 va

lue>ma

x[ls

on] val

ue

>ma

x[ls

on

]時,說明左區間對答案沒有貢獻,答案為 ca

lc(r

son,

valu

e)c al

c(rs

on,v

alue

)。否則,答案為 ca

lc(l

son,

valu

e)+c

alc(

rson

,max

[lso

n]) cal

c(ls

on,v

alue

)+ca

lc(r

son,

max[

lson

])

。我們發現 va

lue≤

max[

lson

] val

ue≤m

ax[l

son]

的時候兩邊都要遞迴下去,時間複雜度時 θ(

n)θ (n

)的,會超時。其實 ca

lc(r

son,

max[

lson

])c al

c(rs

on,m

ax[l

son]

)就是 cn

t[ro

ot]−

cnt[

lson

] cnt

[roo

t]−c

nt[l

son]

(請讀者自行思考)。這樣,我們就得到了乙個 θ(

mlog22

n)θ (m

log22⁡

n)

的演算法。

#include 

#include

#include

using

namespace

std;

typedef pair pii;

const

int maxn = 100005;

const

int maxm = 1

<< 18 | 1;

int n, m, cnt[maxm];

double val[maxn], mx[maxm];

int calc(int u, int l, int r, double x) else

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

int ls = u << 1, rs = ls | 1;

if (x < mx[ls]) else

}void modify(int u, int l, int r, int x, double y, double z)

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

int ls = u << 1, rs = ls | 1;

if (x <= mid) else

mx[u] = max(mx[ls], mx[rs]);

cnt[u] = cnt[ls] + calc(rs, mid + 1, r, mx[ls]);

}int main()

return

0;}

THUSC 2013 樓房重建

維護乙個序列 支援單點修改,定義乙個位置 i 的權值為ai i,要求實時回答最長棧的長度 也就是說從開頭依次選入,若棧為空或大於已選擇的最後乙個元素則選擇,小於等於則捨棄 n 400,000 問題主要是難在如何維護這個最長棧。題解用了比較巧妙的方法,因為它並沒有 維護 這乙個序列。它是類似於樹分治這...

BZOJ2957 樓房重建(線段樹)

這裡放傳送門 可以發現如果一段樓房能被看見,那麼它們跟原點的連線的斜率都是單調遞增的。於是這就變成了乙個維護上公升序列的題。這裡的上公升序列不是最長上公升子串行那樣的東西,而是相當於貪心地選擇,選中的子串行中的每乙個元素它前面都不能存在大於等於它的元素。比如說,有乙個斜率序列是1,2,4,3,4,如...

BZOJ2957 樓房重建 線段樹

題目 time limit 10 sec memory limit 256 mb submit 2259 solved 1069 submit status discuss 小a的樓房外有一大片施工工地,工地上有n棟待建的樓房。每天,這片工地上的房子拆了又建 建了又拆。他經常無聊地看著窗外發呆,數自...