• 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
    ",tr[1].c);
        }
        return 0;
    }

     

  • 相关阅读:
    "V租房"搭建微信租房平台,让租房人发起求租需求并接收合适房源回复,提高租房效率 | 36氪
    金融街
    Jsensation | 氪加
    Polyvore
    周翔宇_百度百科
    鸵鸟心态
    新闻:型牌男装:网上订服装,如何将返修率降到5个点以下 | IT桔子
    【案例】舒邑:一个女装品牌的奇葩打法-@i黑马
    专访OPPO李紫贵:ColorOS用户过千万 软硬融合生态版图初现
    关于我们-EIBOA易博男装-互联网品质男装品牌-在线销售男士西服,衬衫,外套,西裤,领带|全场免运费,30天退换货保障
  • 原文地址:https://www.cnblogs.com/Never-mind/p/8907156.html
Copyright © 2020-2023  润新知