【题解】GSS2 - Can you answer these queries II
思路
扫描线 + 线段树。
似乎是典题,但是只推了一半……
首先发现需要去重,考虑一个离线做法。
将所有的询问离线下来,按右端点排序,扫描线处理。
这里线段树比较玄学,维护的是:
- 令下标为 \(i\) 的位置是 \(i\) 到当前右端点 \(r\) 的贡献。
-
\([i, r]\) 的和。
-
\([i, r]\) 的历史版本最大和。
-
\([i, r]\) 的加法标记。
-
\([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;
}