zoukankan      html  css  js  c++  java
  • BZOJ2957 楼房重建

    Description

    平面上有(n)个位置(1dots n),第(i)个位置有一个高为(H_i)的楼房;所有(H)初始值为(0)。每次修改一个(H_i),求修改后从((0,0))点可以看到多少楼房。(n,mleq10^5)

    Solution

    线段树。

    首先可以发现某个楼房能够被看到当且仅当它的顶点斜率>所有前面的楼房顶点的斜率。

    只记录斜率,把“比前面所有数都大的数”称为“优数”,那么答案即为“优数”的个数

    那么线段树每个节点维护最大值(max)和区内“优数”的个数(ans)

    先考虑查询。我们把查询写成(q(o, x)​)表示查询([l_o,r_o]​)区间(即结点(o​)代表的区间)内比(x​)大的“优数”的个数。

    如果(x)大于等于(max_{lson}),那么(q(o,x)=q(rson, x))。显然。

    否则,(q(o,x)=ans_o - (ans_{lson}-q(lson, x))),即总“优数”个数减去左子区间里小于等于x的“优数”个数。

    再考虑如何维护信息。(max)容易维护。(ans_o=ans_{lson}+q(rson, max_{lson}))即可。

    最终的答案就是(q(root, 0))

    Code

    #include <algorithm>
    #include <cstdio>
    const int N = 100050;
    typedef long long LL;
    struct Frac{
      int x, y;
      Frac(int x = 1, int y = 0) : x(x), y(y) {}
      bool operator<(const Frac &f) const {
        return (LL)y * f.x < (LL)f.y * x;
      }
    }maxv[N * 4];
    int lenv[N * 4], Y[N];
    int query(int o, int l, int r, Frac x) {
      if (!(x < maxv[o])) return 0;
      if (l == r) return 1;
      int mid = (l + r) / 2;
      return maxv[o << 1] < x
        ? query(o << 1 | 1, mid + 1, r, x)
        : query(o << 1, l, mid, x) + lenv[o] - lenv[o << 1];
    }
    void upd(int o, int l, int r) {
      if (l == r) {
        lenv[o] = 1;
        maxv[o] = Frac(l, Y[l]);
      } else {
        int lc = o << 1, rc = o << 1 | 1, mid = (l + r) / 2;
        maxv[o] = std::max(maxv[lc], maxv[rc]);
        lenv[o] = lenv[lc] + query(rc, mid + 1, r, maxv[lc]);
      }
    }
    void modify(int o, int l, int r, int x, int y) {
      if (l > x || r < x) return;
      if (l == r)
        Y[x] = y;
      else {
        int mid = (l + r) / 2;
        modify(o << 1, l, mid, x, y);
        modify(o << 1 | 1, mid + 1, r, x, y);
      }
      upd(o, l, r);
    }
    void build(int o, int l, int r) {
      maxv[o] = Frac(l, 0); lenv[o] = 1;
      if (l != r) {
        int mid = (l + r) / 2;
        build(o << 1, l, mid);
        build(o << 1 | 1, mid + 1, r);
      }
    }
    int main() {
      int n, m, x, y;
      scanf("%d%d", &n, &m);
      build(1, 1, n);
      while (m--) {
        scanf("%d%d", &x, &y);
        modify(1, 1, n, x, y);
        printf("%d
    ", query(1, 1, n, Frac()));
      }
      return 0;
    }
    
  • 相关阅读:
    POJ 2923 Relocation (状态压缩,01背包)
    HDU 2126 Buy the souvenirs (01背包,输出方案数)
    hdu 2639 Bone Collector II (01背包,求第k优解)
    UVA 562 Dividing coins (01背包)
    POJ 3437 Tree Grafting
    Light OJ 1095 Arrange the Numbers(容斥)
    BZOJ 1560 火星藏宝图(DP)
    POJ 3675 Telescope
    POJ 2986 A Triangle and a Circle
    BZOJ 1040 骑士
  • 原文地址:https://www.cnblogs.com/y-clever/p/8513175.html
Copyright © 2011-2022 走看看