• 【BZOJ 2957】 2957: 楼房重建 (线段树)


    2957: 楼房重建

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 1753  Solved: 841

    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

    HINT

    Source

    【分析】

      其实这个很明显是线段树维护的,但是维护方法和求值方法其实都不是很传统,所以我想不到啊。。。

      分析题目知道先把每栋楼跟原点的三角形的斜率求出来,一个楼有贡献当且仅当他的斜率比他前面的楼的斜率都大,即大于前面的楼的斜率的最大值。

      线段树维护一个ans和mx,mx表示这个区间的斜率的最大值,ans表示只考虑这个区间的时候的答案。

      更新ans的时候要带一个外区间的mx,表示前面区间的mx

      若这个mx>=左孩子的mx,则左边都不能选,只考虑右边,变成子问题。

      若这个mx<左孩子的mx,则为整个区间的ans-左区间的ans+左区间带mx时的ans(这个也很容易意会吧)

      【说明我的线段树还是有漏洞啊TAT

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<algorithm>
     6 using namespace std;
     7 #define Maxn 100010
     8 
     9 double mymax(double x,double y) {return x>y?x:y;}
    10 
    11 struct node
    12 {
    13     int l,r,lc,rc;
    14     double mx;
    15     int ans;
    16 }tr[Maxn*2];
    17 int len;
    18 
    19 int build(int l,int r)
    20 {
    21     int x=++len;
    22     tr[x].l=l;tr[x].r=r;tr[x].mx=0;tr[x].ans=0;
    23     if(l!=r)
    24     {
    25         int mid=(l+r)>>1;
    26         tr[x].lc=build(l,mid);
    27         tr[x].rc=build(mid+1,r);
    28     }
    29     else tr[x].lc=tr[x].rc=0;
    30     return x;
    31 }
    32 
    33 int query(int x,double mx)
    34 {
    35     if(tr[x].l==tr[x].r) return tr[x].mx>mx;
    36     int mid=(tr[x].l+tr[x].r)>>1;
    37     if(tr[tr[x].lc].mx<mx) return query(tr[x].rc,mx);
    38     return tr[x].ans-tr[tr[x].lc].ans+query(tr[x].lc,mx);
    39 }
    40 
    41 void change(int x,int y,double z)
    42 {
    43     if(tr[x].l==tr[x].r)
    44     {
    45         tr[x].mx=z;
    46         tr[x].ans=1;
    47         return;
    48     }
    49     int mid=(tr[x].l+tr[x].r)>>1;
    50     if(y<=mid) change(tr[x].lc,y,z);
    51     else change(tr[x].rc,y,z);
    52     tr[x].mx=mymax(tr[tr[x].lc].mx,tr[tr[x].rc].mx);
    53     tr[x].ans=tr[tr[x].lc].ans+query(tr[x].rc,tr[tr[x].lc].mx);
    54 }
    55 
    56 int main()
    57 {
    58     int n,m;
    59     scanf("%d%d",&n,&m);
    60     build(1,n);
    61     for(int i=1;i<=m;i++)
    62     {
    63         int x,y;
    64         scanf("%d%d",&x,&y);
    65         change(1,x,y*1.0/x);
    66         printf("%d
    ",tr[1].ans);
    67     }
    68     return 0;
    69 }
    View Code

    2017-03-25 09:50:54

  • 相关阅读:
    样式
    读取网页图片(包含代理)
    C# 替换“换行符”写法
    Iframe中弹出消息问题
    程序list
    C#对象序列化
    软件工程——个人总结
    软件工程——团队作业4
    软件工程———团队答辩
    软件工程--团队作业三
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/6616043.html
Copyright © 2020-2023  润新知