題解 洛谷P4198 BZOJ2957 樓房重建

2022-03-19 23:55:47 字數 1656 閱讀 6214

每個樓房,還有修改操作。簡單的想到用線段樹來維護資訊。

顯然線段樹只需要維護y/x即可,對於每乙個樓房,能看見的條件就是前面樓房的y/x的嚴格小於當前樓房的y/x。

線段樹的區間修改不再贅述。

那麼怎麼維護可以看到的樓房數呢?

假設現在有一區間:1,5,8,0,7,9。維護這個區間資訊的節點編號為x

x<<1維護的區間是1,5,8,從18看可以看到三個樓房,故x<<1的sum的值為3

x<<1|1維護的區間是0,7,9,從09看也可以看到三個樓房,故x<<1|1的sum的值也為3

這顯然是不能加在一起的,x的sum的值為4。

為什麼會錯呢?應為右兒子x<<1|1的觀察視角不是從1開始的,是從0開始的。

顯然0被擋住了。

顯然,為什麼這道題是紫題,主要難在的怎麼上傳資訊。(不然就是黃牌了)

首先考慮每個線段樹節點在維護乙個mxmx代表這個節點所代表的區間中所有的樓房中最高的高度。

上傳時,由於兩個兒子的sum值是已經處理好的,而左兒子的視角是跟x的視角一樣的(對於上面的例子來說都是1),可以直接上傳,即sum(x)+=sum(x<<1)

對於右兒子,考慮遞迴處理右兒子的區間,遞迴時帶乙個mx變數表示x的左兒子的最高的樓房(右兒子再左兒子後面,原因下面解釋),遞迴的返回值是當前處理區間可以被看到的樓房數(從x的視角看)

對於現在處理的每乙個區間:

#include#define ll long long

#define inf 0x3f3f3f3f

#define lson x<<1

#define rson x<<1|1

using namespace std;

const int n=1e5+2;

struct node tree[n<<2];

int n,m;

double val[n];

inline void pushup_max(int x)

inline int pushup_sum(double mx,int x,int l,int r)

inline void change(int x,int l,int r,int pos,int value)

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

if(pos<=mid)change(lson,l,mid,pos,value);

else if(pos>mid)change(rson,mid+1,r,pos,value);

pushup_max(x);

l(x)=l(lson)+pushup_sum(m(lson),rson,mid+1,r);

}int main()

return 0;

}

洛谷 P4198 樓房重建 題解

題面 首先你要知道題問的是什麼 使用一種資料結構,動態地維護以1為起點地最長上公升子串行 把樓房的高度轉化成斜率地序列 的長度 怎麼做?線段樹!初始化 對於每乙個葉子節點,從這段區間頭可以看到的樓房數量一定為1,區間斜率最大值一定為該點的斜率 在合併時 1.我們可以先查詢右區間的左區間的最大值,如果...

洛谷 P4198 BZOJ 2957 樓房重建

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

洛谷P4198 樓房重建

題意 給定序列,每次修改乙個值,求字首最大值的個數。解 線段樹經典應用。每個節點維護最大值和該區間字首最大值個數。發現我們不用下傳標記,只需要合併區間。需要實現乙個函式int ask l r lm 求出區間 l r 中前乙個數是lm時字首最大值個數。那麼當lm large ls 時,return a...