BZOJ2957 樓房重建

2021-08-14 13:42:57 字數 2049 閱讀 2773

首先顯然可以把點看成斜率,然後就是求乙個從頭開始的最長上公升子串行,支援單點修改。

分塊做法(無腦):

考慮把序列分成

b 塊,每一塊維護乙個從頭開始的最長上公升子串行,並用乙個棧記錄。每次詢問相當於把所有塊掃一遍,在當前塊棧中二分到第乙個大於上一塊最大值的位置,然後貢獻加上其到棧頂的元素個數,複雜度o(

nlogbb

)。修改就直接暴力重構塊,複雜度o(

b)。總複雜度o(

n∗(n

logbb+

b)) 。講道理b=

nlogn−

−−−−

√ 會比較優,不過實測b=

400 最快。。。

線段樹做法(思維):

發現修改乙個點只會對其後面的部分有影響。我們記ma

x 為當前區間最大值,an

s 為只考慮當前區間的答案,考慮如何update,就是如何合併兩個子樹資訊。

考慮當前an

sx應該為an

slso

n ,加上an

srso

n 中大於ma

xlso

n 的部分,於是我們要實現乙個函式ca

l(x,

d)表示

x 中起始值大於

d的最長上公升子串行長度。分兩種情況討論即可: 若l

sonm

ax≤d

,不用考慮左子樹,直接遞迴右子樹即可。 若l

sonm

ax>

d ,答案為ca

l(ls

on,d

)+ca

l(rs

on,m

axls

on) ,但後半部分顯然為an

sx−a

nsls

on,所以只要遞迴左子樹即可。

因為每次update也是o(

logn

) 的,所以總複雜度o(

nlog2n

) 。

分塊**:

#include

#include

#include

#include

#define id(x) (((x)-1)/b+1)

#define l(x) ((x-1)*b+1)

#define r(x) min(n,x*b)

#define ll long long

using

namespace

std;

const

int b=400;

const

int maxn=100010;

int n,m,h[maxn];

bool cmp(int p,int q)

struct block

void rebuild()

int qry(int &last)

}a[id(maxn)+10];

int main()

return

0;}

線段樹**:

#include

#include

#include

using

namespace

std;

const

int maxn=100010;

int n,m;

struct tree

void build(int l,int r)

int cal(int l,int r,double dw)

void mdf(int l,int r,int pl,double d)

int mid=l+r>>1;

if(pl<=mid) ls->mdf(l,mid,pl,d);

else rs->mdf(mid+1,r,pl,d);

mx=max(ls->mx,rs->mx);

s=ls->s+rs->cal(mid+1,r,ls->mx);

}}*xtr;

int main()

return

0;}

bzoj 2957 樓房重建

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

BZOJ2957 樓房重建

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

BZOJ2957 樓房重建

題意 給定m m 100000 個操作,每次將座標軸上橫座標為x 1 x n 100000 的樓的高度設為y,之後回答在 0,0 能看到幾個樓。分析 7.19考試題,當時全場基本都寫得o nm 大暴力,gzz神犇用騙分法竟然ac了,但在bzoj上tle了,只能說考試時候資料水了。這題有兩種做法,一種...