題意轉化:動態維護乙個單調棧,支援單點修改,整體查詢單調棧長度。
使用線段樹。對於每個節點,維護 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棟待建的樓房。每天,這片工地上的房子拆了又建 建了又拆。他經常無聊地看著窗外發呆,數自...