bzoj2957 楼房重建

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 }

 

posted @ 2017-09-09 09:51  wfj_2048  阅读(151)  评论(0编辑  收藏  举报