QOJ.ac

QOJ

Type: Editorial

Status: Open

Posted by: jiangly

Posted at: 2025-12-13 00:36:19

Last updated: 2025-12-13 00:36:27

Back to Problem

题解

题意

有 $N$ ($1\le N\le 3\cdot10^5$) 座城市排成一行,$N-1$ 条道路连接了每一对相邻的城市。第 $i$ 条道路连接了城市 $i$ 和 $i+1$,经过它需要的时间为 $1$ 秒,且只会在 $[L_i,R_i]$ 的时间开放 (因为需要 $1$ 秒通过,所以必须在 $[L_i,R_i-1]$ 的时间出发)。Bitaro 可以使用技能使得时间变为 $1$ 秒前,也可以等待时间自然流逝。接下来有以下两种操作共 $Q$ ($1\le Q\le 3\cdot10^5$) 次:

  • 将道路 $P_i$ 的开放时间改为 $[S_i,T_i]$。
  • 询问 $B_i$ 时刻从城市 $A_i$ 出发,在 $D_i$ 时刻到达城市 $C_i$,最少使用技能的次数。

题解

把 $y$ 时刻在城市 $x$ 的状态看作二维平面上的点 $(x,y)$。不妨设 $A_i< C_i$,则将 $(x,y)$ 变换为 $(x,y-x)$,则问题就转化为了只能向上下右三个方向走 (向左走显然不优),需要的最少的上下走的次数。考虑一个区间的所有 $[L_i,R_i]$ 的限制,如果它们有交,则这个区间等价于它们的交;否则,一定等价于一条路径,即只能从固定的纵坐标进入和离开,并付出一定的代价。用线段树维护每个区间的等价限制即可。

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

代码

#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <functional>
struct Node {
    int l;
    int r;
    long long cost;
    Node(int l = -0x3fffffff, int r = 0x3fffffff, long long cost = -1) : l(l), r(r), cost(cost) {}
    friend Node operator+(const Node &lhs, const Node &rhs) {
        if (lhs.cost == -1 && rhs.cost == -1) {
            if (lhs.l > rhs.r) {
                return Node(lhs.l, rhs.r, lhs.l - rhs.r);
            } else if (lhs.r < rhs.l) {
                return Node(lhs.r, rhs.l, 0);
            } else {
                return Node(std::max(lhs.l, rhs.l), std::min(lhs.r, rhs.r));
            }
        } else if (lhs.cost == -1) {
            if (rhs.l < lhs.l) {
                return Node(lhs.l, rhs.r, rhs.cost + lhs.l - rhs.l);
            } else if (rhs.l > lhs.r) {
                return Node(lhs.r, rhs.r, rhs.cost);
            } else {
                return rhs;
            }
        } else if (rhs.cost == -1) {
            if (lhs.r < rhs.l) {
                return Node(lhs.l, rhs.l, lhs.cost);
            } else if (lhs.r > rhs.r) {
                return Node(lhs.l, rhs.r, lhs.cost + lhs.r - rhs.r);
            } else {
                return lhs;
            }
        } else {
            return Node(lhs.l, rhs.r, lhs.cost + rhs.cost + std::max(lhs.r - rhs.l, 0));
        }
    }
};
struct SegmentTree {
    const int n;
    std::vector<Node> a;
    SegmentTree(int n) : n(n), a(4 * n) {}
    void modify(int p, int l, int r, int pos, int x, int y) {
        if (r - l == 1) {
            a[p] = Node(x, y);
        } else {
            int m = (l + r) / 2;
            if (pos < m) {
                modify(2 * p, l, m, pos, x, y);
            } else {
                modify(2 * p + 1, m, r, pos, x, y);
            }
            a[p] = a[2 * p] + a[2 * p + 1];
        }
    }
    Node rangeSum(int p, int l, int r, int x, int y) {
        if (l >= y || r <= x) {
            return Node();
        } else if (l >= x && r <= y) {
            return a[p];
        } else {
            int m = (l + r) / 2;
            return rangeSum(2 * p, l, m, x, y) + rangeSum(2 * p + 1, m, r, x, y);
        }
    }
    void modify(int p, int x, int y) { modify(1, 0, n, p, x, y); }
    Node rangeSum(int l, int r) { return rangeSum(1, 0, n, l, r); }
};
int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int n, q;
    std::cin >> n >> q;
    SegmentTree t(n - 1), tR(n - 1);
    for (int i = 0; i < n - 1; ++i) {
        int l, r;
        std::cin >> l >> r;
        t.modify(i, l - i, r - i - 1);
        tR.modify(n - 2 - i, l + i + 1, r + i);
    }
    while (q--) {
        int op;
        std::cin >> op;
        if (op == 1) {
            int p, l, r;
            std::cin >> p >> l >> r;
            --p;
            t.modify(p, l - p, r - p - 1);
            tR.modify(n - 2 - p, l + p + 1, r + p);
        } else {
            int a, b, c, d;
            std::cin >> a >> b >> c >> d;
            --a;
            --c;
            if (a < c) {
                std::cout << std::max(0ll, (Node(b - a, b - a) + t.rangeSum(a, c) + Node(d - c, d - c)).cost)
                          << "\n";
            } else {
                std::cout
                    << std::max(
                           0ll,
                           (Node(a + b, a + b) + tR.rangeSum(n - 1 - a, n - 1 - c) + Node(c + d, c + d)).cost)
                    << "\n";
            }
        }
    }
    return 0;
}

Comments

No comments yet.