1 条题解

  • 0
    @ 2026-10-27 4:21:40

    思路与算法

    按右端r离线回答查询。对每个左端l维护A_l=max a[l..r]、B_l=max b[l..r]、P_l=A_lB_l及历史和H_l=∑_{t≤r}max a[l..t]max b[l..t]。加入a_r/b_r时,两个单调栈分别给出需要覆盖赋值的左端后缀区间;线段树支持区间赋A、赋B以及全局H+=P。询问[l,r]取这些左端的H之和。延迟标记将A/B分别保留或赋常量,历史增量表示成pAB+xA+yB+c,组合时把前一个A/B赋值代入后一个多项式。

    正确性说明

    对固定r,单调栈界定前一个更大值位置,之后的所有左端最大值都会变成当前值,之前不变,故两个覆盖赋值准确。更新后P就是本右端所有子数组的目标值,累加到H使其按右端收集全部子数组。查询时只求左端≥l且≤r的H,历史上未激活的左端P为0,因此恰枚举查询区间内全部子数组。标记多项式包含A、B、AB和常数的所有可能历史贡献,对常量代入封闭;按先旧后新的函数复合推导标记,正确下传。

    复杂度

    O((n+Q)log n)时间、O(n+Q)空间,含节点全零、查询桶和两个单调栈初始化。

    易错点

    历史和不能只用当前最大值乘长度。所有乘法、累加及延迟标记都用unsigned long long,自然按2^64取模;输出无符号十进制。赋值标志以0表示未设置,仅因题中排列值均为正才成立。

    参考代码(C++11)

    #include <bits/stdc++.h>
    using namespace std;
    using U = unsigned long long;
    struct Tag {
        U a = 0, b = 0, p = 0, x = 0, y = 0, c = 0;
    };
    struct Node {
        U A = 0, B = 0, P = 0, H = 0;
        Tag tag;
    };
    struct Seg {
        int n;
        vector<Node> t;
        Seg(int n) : n(n), t(4 * n) {
        }
        void apply(int u, int l, int r, Tag z) {
            auto &v = t[u];
            U len = r - l + 1;
            v.H += z.p * v.P + z.x * v.A + z.y * v.B + z.c * len;
            if (z.a && z.b)
                v.P = z.a * z.b * len;
            else if (z.a)
                v.P = z.a * v.B;
            else if (z.b)
                v.P = z.b * v.A;
            if (z.a)
                v.A = z.a * len;
            if (z.b)
                v.B = z.b * len;
            auto &a = v.tag;
            if (a.a && a.b)
                a.c += z.p * a.a * a.b;
            else if (a.a)
                a.y += z.p * a.a;
            else if (a.b)
                a.x += z.p * a.b;
            else
                a.p += z.p;
            if (a.a)
                a.c += z.x * a.a;
            else
                a.x += z.x;
            if (a.b)
                a.c += z.y * a.b;
            else
                a.y += z.y;
            a.c += z.c;
            if (z.a)
                a.a = z.a;
            if (z.b)
                a.b = z.b;
        }
        void push(int u, int l, int r) {
            int m = (l + r) / 2;
            apply(2 * u, l, m, t[u].tag);
            apply(2 * u + 1, m + 1, r, t[u].tag);
            t[u].tag = Tag();
        }
        void pull(int u) {
            t[u].A = t[2 * u].A + t[2 * u + 1].A;
            t[u].B = t[2 * u].B + t[2 * u + 1].B;
            t[u].P = t[2 * u].P + t[2 * u + 1].P;
            t[u].H = t[2 * u].H + t[2 * u + 1].H;
        }
        void update(int u, int l, int r, int L, int R, Tag z) {
            if (L <= l && r <= R) {
                apply(u, l, r, z);
                return;
            }
            push(u, l, r);
            int m = (l + r) / 2;
            if (L <= m)
                update(2 * u, l, m, L, R, z);
            if (R > m)
                update(2 * u + 1, m + 1, r, L, R, z);
            pull(u);
        }
        U query(int u, int l, int r, int L, int R) {
            if (L <= l && r <= R)
                return t[u].H;
            push(u, l, r);
            int m = (l + r) / 2;
            U v = 0;
            if (L <= m)
                v += query(2 * u, l, m, L, R);
            if (R > m)
                v += query(2 * u + 1, m + 1, r, L, R);
            return v;
        }
    };
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int T, n;
        cin >> T >> n;
        vector<int> a(n + 1), b(n + 1);
        for (int i = 1; i <= n; i++)
            cin >> a[i];
        for (int i = 1; i <= n; i++)
            cin >> b[i];
        int Q;
        cin >> Q;
        vector<vector<pair<int, int>>> queries(n + 1);
        for (int i = 0; i < Q; i++) {
            int l, r;
            cin >> l >> r;
            queries[r].push_back({l, i});
        }
        vector<U> ans(Q);
        Seg tree(n);
        vector<int> sa, sb;
        for (int i = 1; i <= n; i++) {
            while (!sa.empty() && a[sa.back()] < a[i])
                sa.pop_back();
            Tag z;
            z.a = a[i];
            tree.update(1, 1, n, sa.empty() ? 1 : sa.back() + 1, i, z);
            sa.push_back(i);
            while (!sb.empty() && b[sb.back()] < b[i])
                sb.pop_back();
            z = Tag();
            z.b = b[i];
            tree.update(1, 1, n, sb.empty() ? 1 : sb.back() + 1, i, z);
            sb.push_back(i);
            z = Tag();
            z.p = 1;
            tree.apply(1, 1, n, z);
            for (auto q : queries[i])
                ans[q.second] = tree.query(1, 1, n, q.first, i);
        }
        for (U x : ans)
            cout << x << "\n";
    }
    
    • 1

    信息

    ID
    1999
    时间
    1000ms
    内存
    512MiB
    难度
    提高+
    标签
    递交数
    0
    已通过
    0
    上传者