每個樓房,還有修改操作。簡單的想到用線段樹來維護資訊。
顯然線段樹只需要維護y/x即可,對於每乙個樓房,能看見的條件就是前面樓房的y/x的嚴格小於當前樓房的y/x。
線段樹的區間修改不再贅述。
那麼怎麼維護可以看到的樓房數呢?
假設現在有一區間:1,5,8,0,7,9
。維護這個區間資訊的節點編號為x
。
x<<1
維護的區間是1,5,8
,從1
往8
看可以看到三個樓房,故x<<1的sum
的值為3
。
x<<1|1
維護的區間是0,7,9
,從0
往9
看也可以看到三個樓房,故x<<1|1的sum
的值也為3
。
這顯然是不能加在一起的,x的sum的值
為4。
為什麼會錯呢?應為右兒子x<<1|1
的觀察視角不是從1開始的,是從0開始的。
顯然0被擋住了。
顯然,為什麼這道題是紫題,主要難在的怎麼上傳資訊。(不然就是黃牌了)
首先考慮每個線段樹節點在維護乙個mx
,mx
代表這個節點所代表的區間中所有的樓房中最高的高度。
上傳時,由於兩個兒子的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...