1. 程式人生 > >bzoj2957 樓房重建

bzoj2957 樓房重建

esp void std upd 二維 tput 大於 正整數 logs

Description

  小A的樓房外有一大片施工工地,工地上有N棟待建的樓房。每天,這片工地上的房子拆了又建、建了又拆。他經常無聊地看著窗外發呆,數自己能夠看到多少棟房子。
  為了簡化問題,我們考慮這些事件發生在一個二維平面上。小A在平面上(0,0)點的位置,第i棟樓房可以用一條連接(i,0)和(i,Hi)的線段表示,其中Hi為第i棟樓房的高度。如果這棟樓房上任何一個高度大於0的點與(0,0)的連線沒有與之前的線段相交,那麽這棟樓房就被認為是可見的。
  施工隊的建造總共進行了M天。初始時,所有樓房都還沒有開始建造,它們的高度均為0。在第i天,建築隊將會將橫坐標為Xi的房屋的高度變為Yi(高度可以比原來大---修建,也可以比原來小---拆除,甚至可以保持不變---建築隊這天什麽事也沒做)。請你幫小A數數每天在建築隊完工之後,他能看到多少棟樓房?

Input

  第一行兩個正整數N,M
  接下來M行,每行兩個正整數Xi,Yi

Output

  M行,第i行一個整數表示第i天過後小A能看到的樓房有多少棟

Sample Input

3 4
2 4
3 6
1 1000000000
1 1

Sample Output

1
1
1
2
數據約定
  對於所有的數據1<=Xi<=N,1<=Yi<=10^9
N,M<=100000

正解:線段樹。

其實去年的聯賽模擬就考過這題了,比較無聊所以重做一遍。。

這是一個線段樹的板子題,首先我們考慮維護一個區間的可見點數$sum$,那麽答案就是$sum[rt]$。

如何在單點修改以後維護$sum$?我們考慮一個區間的$sum$,首先左兒子的$sum$肯定是直接加上的。

同時記$max1$為左兒子的斜率最大值,我們可以遞歸右兒子來找右兒子對這個區間的貢獻。

$max2$為右兒子的左兒子的斜率最大值,如果$max2<max1$,那麽我們可以不用管右兒子的左兒子了,直接遞歸右兒子的右兒子即可。

如果$max2>max1$,我們可以發現,右兒子的右兒子的貢獻就是右兒子的右兒子在右兒子這個區間的貢獻,也就是$sum[rs]-sum[ls[rs]]$,那麽直接遞歸右兒子的左兒子計算即可。

到葉子結點的時候直接判斷斜率大小關系就行了。

 1
#include <bits/stdc++.h> 2 #define il inline 3 #define RG register 4 #define ll long long 5 #define N (200010) 6 #define ls (x<<1) 7 #define rs (x<<1|1) 8 #define eps (1e-10) 9 10 using namespace std; 11 12 int sum[N<<2],n,m; 13 double mx[N<<2],k; 14 15 il int gi(){ 16 RG int x=0,q=1; RG char ch=getchar(); 17 while ((ch<0 || ch>9) && ch!=-) ch=getchar(); 18 if (ch==-) q=-1,ch=getchar(); 19 while (ch>=0 && ch<=9) x=x*10+ch-48,ch=getchar(); 20 return q*x; 21 } 22 23 il int calc(RG int x,RG int l,RG int r,RG double k){ 24 if (l==r) return mx[x]>k; RG int mid=(l+r)>>1; 25 if (k<mx[ls]) return calc(ls,l,mid,k)+sum[x]-sum[ls]; 26 else return calc(rs,mid+1,r,k); 27 } 28 29 il void update(RG int x,RG int l,RG int r,RG int p,RG double k){ 30 if (l==r){ mx[x]=k,sum[x]=fabs(k)>=eps; return; } RG int mid=(l+r)>>1; 31 p<=mid ? update(ls,l,mid,p,k) : update(rs,mid+1,r,p,k); 32 sum[x]=sum[ls]+calc(rs,mid+1,r,mx[ls]),mx[x]=max(mx[ls],mx[rs]); return; 33 } 34 35 int main(){ 36 #ifndef ONLINE_JUDGE 37 freopen("rebuild.in","r",stdin); 38 freopen("rebuild.out","w",stdout); 39 #endif 40 n=gi(),m=gi(); 41 for (RG int i=1,x,y;i<=m;++i){ 42 x=gi(),y=gi(),k=1.0*y/x; 43 update(1,1,n,x,k),printf("%d\n",sum[1]); 44 } 45 return 0; 46 }

bzoj2957 樓房重建