bzoj 2957 樓房重建

2021-08-26 02:28:44 字數 1594 閱讀 6525

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

為了簡化問題,我們考慮這些事件發生在乙個二維平面上。小a在平面上(0,0)點的位置,第i棟樓房可以用一條連線(i,0)和(i,hi)的線段表示,其中hi為第i棟樓房的高度。如果這棟樓房上任何乙個高度大於0的點與(0,0)的連線沒有與之前的線段相交,那麼這棟樓房就被認為是可見的。 

施工隊的建造總共進行了m天。初始時,所有樓房都還沒有開始建造,它們的高度均為0。在第i天,建築隊將會將橫座標為xi的房屋的高度變為yi(高度可以比原來大—修建,也可以比原來小—拆除,甚至可以保持不變—建築隊這天什麼事也沒做)。請你幫小a數數每天在建築隊完工之後,他能看到多少棟樓房?

思路:線段樹,點修改。 求遞增的數有多少個。 滿足後乙個點的斜率大於前乙個點的斜率。

我們線段樹維護兩個值。最大的斜率,能看到的樓房的個數,就是遞增的值。

我們修改點,然後更新父親節點的時候,我們要注意一下,

左兒子可以直接加上。然後右區間的樓房可能被左區間的樓房遮住。

判斷右區間。 設左兒子的最大斜率是 m、 右區間的左兒子的最大斜率為 mm。

如果 m > mm 。 說明右區間的左兒子全部被遮住。就乙個也看不到。所以我們在找右區間的右兒子。

如果 m< mm. 這就說明我們知道了右區間的右兒子的值了, 就是 右區間的值 - 右區間的左兒子的值。

然後我們在找右區間的左兒子的值。

#include #define mem(x,v) memset(x,v,sizeof(x)) 

#define mid(x,y) ((x + y) >> 1)

#define go(i,a,b) for (int i = a; i <= b; i++)

#define og(i,a,b) for (int i = a; i >= b; i--)

using namespace std;

typedef long long ll;

const double eps = 1e-10;

const int inf = 0x3f3f3f3f;

const int n = 1e5+1000;

int val[n*4];

double rake[n*4];

int n,m;

void build(int now, int a, int b)

int query(int now, int a, int b, double k)

void insert(int now, int a,int b,int l, double k)

int m = mid(a,b);

if (l < m) insert(now*2,a,m,l,k);

if (l >= m) insert(now*2+1,m,b,l,k);

rake[now] = max(rake[now*2],rake[now*2+1]);

val[now] = val[now*2] + query(now*2+1,m,b,rake[now*2]);

}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了,只能說考試時候資料水了。這題有兩種做法,一種...