BZOJ2957: 楼房重建

【传送门:BZOJ2957


简要题意:

  给出一个平面直角坐标系,有一个人站在(0,0)处,x轴的取值范围为1<=x<=n

  有m个操作,每个操作输入x,y,表示在(x,0)处建一座楼,高y,如果(x,0)处本来没有楼则看作新建,否则看作改造

  对于一座楼房,它能被看到当且仅当它的最高点与(0,0)的连线没有与其他楼有交点

  求出每次操作后,这个人能看到的楼房数


题解:

  线段树好题

  对于一个楼房被看到,可以看作它与(0,0)的连线的斜率比前面所有的斜率都大

  那么我们可以把每次操作都当成单点修改,然后求整段区间从第一个楼房开始斜率递增所得到的楼房数

  设mx为每个区间中最大的斜率,c为每个区间从左端点开始能看到的楼房数

  显然我们需要在修改的时候维护线段树

  对于一段区间,显然左子区间的c值的贡献一定全部在整段区间的c值中,所以我们只要对右子区间进行处理

  如果当前左子区间的最大值>=右子区间的最大值,那么右子区间对整段区间是没有贡献的

  不然则在右子区间中找出以第一个大于左子区间的最大值的楼房,然后贡献为从这个楼房往后得到的楼房数(包括这个楼房)

  就这样,注意一下精度就可以了


参考代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#define eps 1e-10
using namespace std;
struct trnode
{
    int l,r,lc,rc,c;
    double mx;
}tr[210000];int trlen;
void bt(int l,int r)
{
    int now=++trlen;
    tr[now].l=l;tr[now].r=r;
    tr[now].lc=tr[now].rc=-1;
    tr[now].c=0;tr[now].mx=0.0;
    if(l<r)
    {
        int mid=(l+r)/2;
        tr[now].lc=trlen+1;bt(l,mid);
        tr[now].rc=trlen+1;bt(mid+1,r);
    }
}
int ans;
void findd(int now,double d)
{
    if(tr[now].l==tr[now].r){ans++;return ;}
    int lc=tr[now].lc,rc=tr[now].rc;
    if(tr[lc].mx<=d) findd(rc,d);
    else ans+=tr[now].c-tr[lc].c,findd(lc,d);
}
void follow(int now)
{
    int lc=tr[now].lc,rc=tr[now].rc;
    tr[now].c=tr[lc].c;tr[now].mx=tr[lc].mx;
    if(tr[rc].mx-tr[lc].mx>eps)
    {
        tr[now].mx=tr[rc].mx;
        ans=0;findd(rc,tr[lc].mx);
        tr[now].c+=ans;
    }
}
void change(int now,int x,double d)
{
    if(tr[now].l==tr[now].r)
    {
        tr[now].mx=d;
        tr[now].c=1;
        return ;
    }
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(x<=mid) change(lc,x,d);
    else change(rc,x,d);
    follow(now);
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    trlen=0;bt(1,n);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        change(1,x,double(y)/double(x));
        printf("%d\n",tr[1].c);
    }
    return 0;
}

 

posted @ 2018-04-22 14:31  Star_Feel  阅读(132)  评论(0编辑  收藏  举报