Luogu4198 樓房重建

2021-10-19 10:54:24 字數 2927 閱讀 7170

小 a 的樓房外有一大片施工工地,工地上有 n

nn 棟待建的樓房。每天,這片工地上的房子拆了又建、建了又拆。他經常無聊地看著窗外發呆,數自己能夠看到多少棟房子。

為了簡化問題,我們考慮這些事件發生在乙個二維平面上。小 a 在平面上 (0,

0)

(0,0)

(0,0

) 點的位置,第 i

ii 棟樓房可以用一條連線 (i,

0)

(i,0)

(i,0

) 和 (i,

hi

)(i,h_i)

(i,hi​

) 的線段表示,其中 h

ih_i

hi​ 為第 i

ii 棟樓房的高度。如果這棟樓房上任何乙個高度大於 0

00 的點與 (0,

0)

(0,0)

(0,0

) 的連線沒有與之前的線段相交,那麼這棟樓房就被認為是可見的。

施工隊的建造總共進行了 m

mm 天。初始時,所有樓房都還沒有開始建造,它們的高度均為 0

00。在第 i

ii 天,建築隊將會將橫座標為 x

ix_i

xi​ 的房屋的高度變為 y

iy_i

yi​(高度可以比原來大—修建,也可以比原來小—拆除,甚至可以保持不變—建築隊這天什麼事也沒做)。請你幫小 a 數數每天在建築隊完工之後,他能看到多少棟樓房?

第一行兩個正整數 n,m

n,mn,

m。接下來 m

mm 行,每行兩個正整數 xi,

yi

x_i,y_i

xi​,yi

​ 。m

mm 行,第 i

ii 行乙個整數表示第 i

ii 天過後小 a 能看到的樓房有多少棟。

輸入 #1

3 42 4

3 61 1000000000

1 1輸出 #111

12對於 100

%100\%

100%

的資料,1≤x

i≤

n1 \le x_i \le n

1≤xi​≤

n,1≤yi

≤109

1 \le y_i \le 10^9

1≤yi​≤

109,1≤n

,m≤1

05

1\le n,m \le 10^5

1≤n,m≤

105。

首先,要判斷乙個樓房是否能被看到,肯定不能去判斷什麼「是否有交點」,稍微一想,就可以想到使用斜率,當某座樓左側沒有斜率比它大的樓時,它就可以被看到。

當把問題「斜率化」之後,問題就變為求乙個上公升子串行的長度,該子串行中的每個元素大於原序列中位於它左側的任意元素,需要支援單點修改和全域性查詢,於是嘗試線段樹。

因為只有單點修改和全域性查詢,所以整棵線段樹不需要什麼打標記、pushdown什麼的,只要能合併子區間資訊就行了。

那麼現在考慮,已知兩個子節點的上公升子串行長度,如何得到父節點的最長上公升子串行長度。

先看左兒子,因為是從左側向右側觀測,所以左兒子的上公升子串行一定是父節點上公升子串行的一部分,而右兒子的上公升子串行要拼接到左兒子的序列上,就應該是從大於左兒子上公升子串行最右端的值開始接到左兒子的上公升子串行上。要找到這個「劃分點」,就需要討論左兒子的最大值k

kk和右兒子v

vv中值的關係。如果k

≥k\ge

k≥tree[v].mx,那麼右兒子的序列會被全部擋住,直接返回左兒子即可;如果k

<

k<

k<

tree[v].mx,則進一步討論k

kk和右兒子的左兒子的關係:若k

≥k\ge

k≥tree[ls].mx那麼右兒子的左兒子是會被擋住的,直接遞迴右兒子;反之,「劃分點」就在右兒子的左兒子裡,就遞迴左兒子,找到斷點後加上右兒子的右兒子中屬於右兒子本身的上公升子串行的部分(比較拗口,用符號表示就是不能加tree[rs].len,而是加上tree[v].len-tree[ls].len)。

由於這個更新區間資訊的過程是遞迴的,所以總複雜度為o(n

log2

2n

)o(nlog_2^2n)

o(nlog

22​n

)。

#include

#define ls v<<1

#define rs v<<1|1

using

namespace std;

const

int m=

1e5+5;

struct nodetree[m<<2]

;int n,m;

void

build

(int v,

int le,

int ri)

intask

(int v,

double k)

void

modify

(int v,

int x,

double k)

if(x<=tree[ls]

.ri)

modify

(ls,x,k)

;else

modify

(rs,x,k)

; tree[v]

.mx=

max(tree[ls]

.mx,tree[rs]

.mx)

; tree[v]

.len=tree[ls]

.len+

ask(rs,tree[ls]

.mx);}

voidin(

)voidac(

)}intmain()

Luogu4198 樓房重建

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

Luogu 4198 樓房重建

bzoj 2957 挺妙的題。先把題目中的要求轉化為斜率,乙個點 x,y 可以看成 frac 這樣子我們要求的就變成了乙個區間內一定包含第乙個值的最長上公升序列。然後把這個序列開成線段樹,維護一下區間內的答案 res 和最大值 mx 顯然對於葉子結點有 mx a l res 1 mx 的更新非常簡單...

洛谷 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 ...