zoukankan      html  css  js  c++  java
  • 【经典问题】bzoj2957: 楼房重建

    经典问题:动态维护上升子序列长度

    进阶问题:【经典问题】#176. 栈

    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能看到的楼房有多少栋

    数据约定
      对于所有的数据1<=Xi<=N,1<=Yi<=10^9
    N,M<=100000


    题目分析

    线段树的巧妙应用:对于每一个线段树区间记录最大值$mx$和以其左端点为起点的答案$ans$。

    考虑信息如何合并:对于区间rt,首先肯定继承了rt.lson的答案,再者若rt.rson的最大值rson.mx<lson.mx,也即右区间再不会被访问到了;否则考虑rson的两个子区间,如果rson.lson.mx<lson.mx只需考虑rson.rson,反之答案就是rson.ans(原先rson两个区间的答案和)-rson.lson.ans(现在以rt.lson.mx为起点,需要重新计算rson.lson的贡献;剩下的rson.rson.ans由于是以rson.lson为起点,那么必定是考虑完rson.lson.mx的答案之后的贡献,因此不必改变)+calc(rson.lson)($ ext{calc}$即重复以上的统计过程)。

    图示如上:

    (话说第一发居然因为eps开太小WA了一次)

     1 #include<bits/stdc++.h>
     2 const int maxn = 100035;
     3 const double eps = 1e-50;
     4 
     5 struct node
     6 {
     7     int ans;
     8     double mx;
     9 }f[maxn<<2];
    10 int n,m;
    11 
    12 int read()
    13 {
    14     char ch = getchar();
    15     int num = 0, fl = 1;
    16     for (; !isdigit(ch); ch=getchar())
    17         if (ch=='-') fl = -1;
    18     for (; isdigit(ch); ch=getchar())
    19         num = (num<<1)+(num<<3)+ch-48;
    20     return num*fl;
    21 }
    22 int calc(int rt, int l, int r, double c)
    23 {
    24     if (l==r) return f[rt].mx > c;
    25     int mid = (l+r)>>1;
    26     if (f[rt<<1].mx-c <= eps) return calc(rt<<1|1, mid+1, r, c);
    27     return f[rt].ans-f[rt<<1].ans+calc(rt<<1, l, mid, c);
    28 }
    29 void modify(int rt, int l, int r, int pos, double c)
    30 {
    31     if (l==r) f[rt].ans = 1, f[rt].mx = c;
    32     else{
    33         int mid = (l+r)>>1;
    34         if (pos <= mid) modify(rt<<1, l, mid, pos, c);
    35         else modify(rt<<1|1, mid+1, r, pos, c);
    36         f[rt].mx = std::max(f[rt<<1].mx, f[rt<<1|1].mx);
    37         f[rt].ans = f[rt<<1].ans+calc(rt<<1|1, mid+1, r, f[rt<<1].mx);
    38     }
    39 }
    40 int main()
    41 {
    42     n = read(), m = read();
    43     for (; m; --m)
    44     {
    45         int x = read(), y = read();
    46         modify(1, 1, n, x, 1.0*y/x);
    47         printf("%d
    ",f[1].ans);
    48     }
    49     return 0;
    50 }

    END

  • 相关阅读:
    《Java数据结构与算法》笔记CH43用栈实现分隔符匹配
    《Java数据结构与算法》笔记CH2无序数组
    《Java数据结构与算法》笔记CH3简单排序
    《Java数据结构与算法》笔记CH41栈的实现
    《Java数据结构与算法》笔记CH42用栈实现字符串反转
    java流程控制.3循环结构
    java方法.1方法的定义和调用
    java流程控制.1scanner
    java方法.2方法的重载
    java方法.3递归
  • 原文地址:https://www.cnblogs.com/antiquality/p/10712779.html
Copyright © 2011-2022 走看看