QOJ.ac

QOJ

Type: Editorial

Status: Open

Posted by: jiangly

Posted at: 2025-12-13 00:33:13

Last updated: 2025-12-13 00:33:42

Back to Problem

New Editorial for Problem #65

题意

有 $N$ ($2\le N\le 2\cdot10^5$) 个天线排成一行,相邻两个天线的距离为 $1$,第 $i$ 个天线的高度为 $H_i$。第 $i$ 个天线只能向与它的距离在区间 $[A_i,B_i]$ 中的天线发送消息。如果两个天线 $i$, $j$ 可以互相发消息,则定义它们的通信成本为 $|H_i-H_j|$。接下来有 $Q$ ($1\le Q\le 2\cdot10^5$) 个询问,第 $i$ 个询问为区间 $[L_i,R_i]$ 中可以互相发消息的天线对的最大通信成本 (如果不存在则为 $-1$)。

题解

不妨将询问改为求最大的 $H_i-H_j$ ($i < j$),则重复两遍该过程即可得到答案。维护两个数组 $P_i$, $Q_i$,初始时都为 $-\infty$。从左到右枚举右端点,在 $i+A_i$ 处将 $P_i$ 修改为 $H_i$,在 $i+B_i+1$ 处将 $P_i$ 修改为 $-\infty$。假设枚举到的右端点为 $j$,则对所有的 $j-B_j\le i\le j-A_j$,$Q_i\gets \max\{Q_i,P_i-H_j\}$。当枚举到 $R_i$ 时,求出 $\max\{Q_k\mid L_i\le k\le R_i \}$ 即为答案。所有操作都可以用线段树维护。

时间复杂度:$O((N+Q)\log N)$。

#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <functional>
constexpr int INF = 1e9;
struct SegmentTree {
    const int n;
    std::vector<int> maxA, maxB, tag;
    SegmentTree(int n) : n(n), maxA(4 * n, -INF), maxB(4 * n, -INF), tag(4 * n, -INF) {}
    void pull(int p) {
        maxA[p] = std::max(maxA[2 * p], maxA[2 * p + 1]);
        maxB[p] = std::max(maxB[2 * p], maxB[2 * p + 1]);
    }
    void add(int p, int v) {
        tag[p] = std::max(tag[p], v);
        maxB[p] = std::max(maxB[p], maxA[p] + v);
    }
    void push(int p) {
        add(2 * p, tag[p]);
        add(2 * p + 1, tag[p]);
        tag[p] = -INF;
    }
    void modifyA(int p, int l, int r, int pos, int v) {
        if (r - l == 1) {
            maxA[p] = v;
            return;
        }
        int m = (l + r) / 2;
        push(p);
        if (pos < m) {
            modifyA(2 * p, l, m, pos, v);
        } else {
            modifyA(2 * p + 1, m, r, pos, v);
        }
        pull(p);
    }
    void rangeModify(int p, int l, int r, int x, int y, int v) {
        if (l >= y || r <= x)
            return;
        if (l >= x && r <= y) {
            add(p, v);
            return;
        }
        int m = (l + r) / 2;
        push(p);
        rangeModify(2 * p, l, m, x, y, v);
        rangeModify(2 * p + 1, m, r, x, y, v);
        pull(p);
    }
    int rangeMaxB(int p, int l, int r, int x, int y) {
        if (l >= y || r <= x)
            return -INF;
        if (l >= x && r <= y)
            return maxB[p];
        int m = (l + r) / 2;
        push(p);
        return std::max(rangeMaxB(2 * p, l, m, x, y), rangeMaxB(2 * p + 1, m, r, x, y));
    }
    void modifyA(int pos, int v) { modifyA(1, 0, n, pos, v); }
    void rangeModify(int l, int r, int v) { rangeModify(1, 0, n, l, r, v); }
    int rangeMaxB(int l, int r) { return rangeMaxB(1, 0, n, l, r); }
};
int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int n;
    std::cin >> n;
    std::vector<int> h(n), a(n), b(n);
    for (int i = 0; i < n; ++i) std::cin >> h[i] >> a[i] >> b[i];
    int q;
    std::cin >> q;
    std::vector<int> l(q), r(q);
    for (int i = 0; i < q; ++i) {
        std::cin >> l[i] >> r[i];
        --l[i];
    }
    std::vector<int> ans(q, -1);
    auto solve = [&]() {
        std::vector<std::vector<int>> queries(n);
        for (int i = 0; i < q; ++i) queries[r[i] - 1].push_back(i);
        std::vector<std::vector<std::pair<int, int>>> mod(n);
        for (int i = 0; i < n; ++i) {
            if (i + a[i] < n)
                mod[i + a[i]].emplace_back(i, h[i]);
            if (i + b[i] + 1 < n)
                mod[i + b[i] + 1].emplace_back(i, -INF);
        }
        SegmentTree t(n);
        for (int i = 0; i < n; ++i) {
            for (auto [pos, v] : mod[i]) t.modifyA(pos, v);
            t.rangeModify(std::max(0, i - b[i]), std::max(0, i - a[i] + 1), -h[i]);
            for (auto j : queries[i]) ans[j] = std::max(ans[j], t.rangeMaxB(l[j], r[j]));
        }
    };
    solve();
    std::reverse(h.begin(), h.end());
    std::reverse(a.begin(), a.end());
    std::reverse(b.begin(), b.end());
    for (int i = 0; i < q; ++i) {
        l[i] = n - l[i];
        r[i] = n - r[i];
        std::swap(l[i], r[i]);
    }
    solve();
    for (int i = 0; i < q; ++i) std::cout << ans[i] << "\n";
    return 0;
}

Comments

No comments yet.