Solution 「洛谷 P4198」楼房重建

\(\mathcal{Description}\)

  Link.

  给定点集 \(\{P_n\}\)\(P_i=(i,h_i)\)\(m\) 次修改,每次修改某个 \(h_i\),在每次修改后求出 \((0,0)\cup\{P_n\}\) 的下凸壳大小(输出时 \(-1\))。

  \(n,m\le10^5\)\(h_i\ge0\)

\(\mathcal{Solution}\)

  令 \(k_i=\frac{h_i}{i}\),我们相当于要维护 \(\{k_n\}\) 中从 \(k_1\) 开始的最长贪心上升子序列 (LGIS?)。

  这是一个动态维护 LGIS 的常见 trick:建一棵序列线段树,对于结点 \(u\),维护区间最大值 \(x_u\) 以及以左区间的最大值为起始的,在右区间中的 LGIS 长度(不包括左区间最大值,故实际值为长度 \(-1\))。

  维护过程,需要支持形如“在 \(u\) 区间内,仅考虑不小于 \(x\) 的值,LGIS 长度”的查询,利用已维护信息可以 \(\mathcal O(\log n)\) 树上查询解决,所以每次标记上传是 \(\mathcal O(\log n)\) 的,一次修改即 \(\mathcal O(\log^2 n)\),总复杂度为 \(\mathcal O(m\log^2n)\)

\(\mathcal{Code}\)

/*+Rainybunny+*/

#include <bits/stdc++.h>

#define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
#define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i)

const int MAXN = 1e5;
const double EPS = 1e-7;
int n, m, val[MAXN + 5];

inline double dabs(const double u) { return u < 0 ? -u : u; }
inline double dmax(const double u, const double v) { return u < v ? v : u; }
inline int dcmp(const double u) { return dabs(u) < EPS ? 0 : u < 0 ? -1 : 1; }

#define DR const int u, const int l, const int r
#define SR 1, 1, n
struct SegmentTree {
    double mx[MAXN << 2];
    int lgis[MAXN << 2];

    inline int calc(DR, const double x) {
        if (l == r) return dcmp(val[l] - x * l) == 1;
        int mid = l + r >> 1;
        if (~dcmp(mx[u << 1] - x)) return calc(u << 1, l, mid, x) + lgis[u];
        return calc(u << 1 | 1, mid + 1, r, x);
    }

    inline void pushup(DR) {
        mx[u] = dmax(mx[u << 1], mx[u << 1 | 1]);
        if (l != r) lgis[u] = calc(u << 1 | 1, l + r + 2 >> 1, r, mx[u << 1]);
    }

    inline void modify(DR, const int x, const int v) {
        if (l == r) return val[l] = v, mx[u] = 1. * val[l] / l, void();
        int mid = l + r >> 1;
        if (x <= mid) modify(u << 1, l, mid, x, v);
        else modify(u << 1 | 1, mid + 1, r, x, v);
        pushup(u, l, r);
    }
} sgt;

int main() {
    std::ios::sync_with_stdio(false), std::cin.tie(0);

    std::cin >> n >> m;
    rep (i, 1, m) {
        int x, y; std::cin >> x >> y;
        sgt.modify(SR, x, y), std::cout << sgt.calc(SR, 0.) << '\n';
    }
    return 0;
}

原文地址:https://www.cnblogs.com/rainybunny/p/15556836.html