Loading

【题解】GSS2 - Can you answer these queries II

思路

扫描线 + 线段树。

似乎是典题,但是只推了一半……

首先发现需要去重,考虑一个离线做法。

将所有的询问离线下来,按右端点排序,扫描线处理。

这里线段树比较玄学,维护的是:

  • 令下标为 \(i\) 的位置是 \(i\) 到当前右端点 \(r\) 的贡献。
  1. \([i, r]\) 的和。

  2. \([i, r]\) 的历史版本最大和。

  3. \([i, r]\) 的加法标记。

  4. \([i, r]\) 的历史版本最大加法标记。

这里实际上是相当于令下标为 \(i\) 的位置动态维护从 \(i\) 开始的最大子段和,将当前拼接的若干右端点存在 3 和 4 中,当拼接更优时就拼接上去。

考虑一下去重,令 \(p(u)\) 表示颜色 \(u\) 上一次出现的下标,那么当前右端点的影响区间就是 \((p(a_r), r]\).

线段树维护一下就行,时间复杂度 \(O(n \log n + q \log q)\)

代码

#include <cstdio>
#include <unordered_map>
#include <algorithm>
using namespace std;

typedef long long ll;

const int maxn = 1e5 + 5;
const int maxq = 1e5 + 5;

namespace SGT
{
    #define lc (k << 1)
    #define rc (k << 1 | 1)

    struct node
    {
        ll sum = 0ll, hmx = 0ll, stag = 0ll, htag = 0ll;

        node operator + (const node& rhs) const
        {
            node res;
            res.sum = max(sum, rhs.sum);
            res.hmx = max(hmx, rhs.hmx);
            return res;
        }
    } tree[maxn << 2];

    void push_up(int k) { tree[k] = tree[lc] + tree[rc]; }

    void push_down(int k, int l, int r)
    {
        int mid = (l + r) >> 1;
        tree[lc].hmx = max(tree[lc].hmx, tree[lc].sum + tree[k].htag);
        tree[rc].hmx = max(tree[rc].hmx, tree[rc].sum + tree[k].htag);
        tree[lc].sum += tree[k].stag;
        tree[rc].sum += tree[k].stag;
        tree[lc].htag = max(tree[lc].htag, tree[lc].stag + tree[k].htag);
        tree[rc].htag = max(tree[rc].htag, tree[rc].stag + tree[k].htag);
        tree[lc].stag += tree[k].stag;
        tree[rc].stag += tree[k].stag;
        tree[k].stag = tree[k].htag = 0ll;
    }

    void update(int k, int l, int r, int ql, int qr, int w)
    {
        if ((l >= ql) && (r <= qr))
        {
            tree[k].sum += w, tree[k].stag += w;
            tree[k].hmx = max(tree[k].hmx, tree[k].sum), tree[k].htag = max(tree[k].htag, tree[k].stag);
            return;
        }
        push_down(k, l, r);
        int mid = (l + r) >> 1;
        if (ql <= mid) update(lc, l, mid, ql, qr, w);
        if (qr > mid) update(rc, mid + 1, r, ql, qr, w);
        push_up(k);
    }

    node query(int k, int l, int r, int ql, int qr)
    {
        if ((l >= ql) && (r <= qr)) return tree[k];
        push_down(k, l, r);
        int mid = (l + r) >> 1;
        if (qr <= mid) return query(lc, l, mid, ql, qr);
        if (ql > mid) return query(rc, mid + 1, r, ql, qr);
        return query(lc, l, mid, ql, qr) + query(rc, mid + 1, r, ql, qr);
    }
}

struct Query
{
    int l, r, idx;

    bool operator < (const Query& rhs) const { return (r < rhs.r); }
} qry[maxq];

int n, q;
int a[maxn];
ll ans[maxq];
unordered_map<int, int> lst;

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    scanf("%d", &q);
    for (int i = 1; i <= q; i++)
    {
        qry[i].idx = i;
        scanf("%d%d", &qry[i].l, &qry[i].r);
    }
    sort(qry + 1, qry + q + 1);
    for (int i = 1, j = 1; i <= q; i++)
    {
        for ( ; j <= qry[i].r; j++)
        {
            SGT::update(1, 1, n, lst[a[j]] + 1, j, a[j]);
            lst[a[j]] = j;
        }
        ans[qry[i].idx] = SGT::query(1, 1, n, qry[i].l, qry[i].r).hmx;
    }
    for (int i = 1; i <= q; i++) printf("%lld\n", ans[i]);
    return 0;
}
posted @ 2023-01-13 19:48  kymru  阅读(59)  评论(0编辑  收藏  举报