洛谷 SP1557 / SPOJ GSS2 Can you answer these queries II
思路
看到去重想到离线。将所有询问按右端点升序排序。设 \(lst_i\) 为 \(a_j = a_i\) 且 \(j < i\) 的最大 \(j\),若不存在则 \(lst_i = 0\)。\(b_j\) 表示 \(\sum\limits_{k=j}^i a_k\),当枚举到 \(i\) 时,将 \(j \in [lst_i + 1,i]\) 的 \(b_j \gets b_j + a_i\),这样就实现了去重。然后处理所有以 \(i\) 为右端点的询问,设为 \([l,i]\),则答案为 \(b\) 数组 \([l,i]\) 的历史最大值。为什么是历史最大值?因为如果是当前最大值,那么就默认子段的右端点为 \(i\),不是最优的。
查询历史最大值,要维护 \(mx,tag,hmx,htag\)。\(mx\) 表示当前最大值,\(tag\) 表示加的懒标记,\(hmx\) 表示历史最大值,\(htag\) 表示历史 \(tag\) 的最大值。pushdown
时就是这样:
void pushdown(int x) {
if (tree[x].htag) {
tree[x << 1].hmx = max(tree[x << 1].hmx, tree[x << 1].mx + tree[x].htag);
tree[x << 1 | 1].hmx = max(tree[x << 1 | 1].hmx, tree[x << 1 | 1].mx + tree[x].htag);
tree[x << 1].htag = max(tree[x << 1].htag, tree[x << 1].tag + tree[x].htag);
tree[x << 1 | 1].htag = max(tree[x << 1 | 1].htag, tree[x << 1 | 1].tag + tree[x].htag);
tree[x].htag = 0;
}
if (tree[x].tag) {
tree[x << 1].mx += tree[x].tag;
tree[x << 1 | 1].mx += tree[x].tag;
tree[x << 1].tag += tree[x].tag;
tree[x << 1 | 1].tag += tree[x].tag;
tree[x].tag = 0;
}
}
其他细节见代码。
代码
code
/*
p_b_p_b txdy
AThousandMoon txdy
AThousandSuns txdy
hxy txdy
*/
#include <bits/stdc++.h>
#define pb push_back
#define fst first
#define scd second
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 100100;
ll n, m, a[maxn], ans[maxn], lst[maxn], pre[maxn << 1];
vector<pii> qq[maxn];
struct node {
ll tag, mx, htag, hmx;
} tree[maxn << 2];
void pushup(int x) {
tree[x].mx = max(tree[x << 1].mx, tree[x << 1 | 1].mx);
tree[x].hmx = max(tree[x << 1].hmx, tree[x << 1 | 1].hmx);
}
void pushdown(int x) {
if (tree[x].htag) {
tree[x << 1].hmx = max(tree[x << 1].hmx, tree[x << 1].mx + tree[x].htag);
tree[x << 1 | 1].hmx = max(tree[x << 1 | 1].hmx, tree[x << 1 | 1].mx + tree[x].htag);
tree[x << 1].htag = max(tree[x << 1].htag, tree[x << 1].tag + tree[x].htag);
tree[x << 1 | 1].htag = max(tree[x << 1 | 1].htag, tree[x << 1 | 1].tag + tree[x].htag);
tree[x].htag = 0;
}
if (tree[x].tag) {
tree[x << 1].mx += tree[x].tag;
tree[x << 1 | 1].mx += tree[x].tag;
tree[x << 1].tag += tree[x].tag;
tree[x << 1 | 1].tag += tree[x].tag;
tree[x].tag = 0;
}
}
void update(int rt, int l, int r, int ql, int qr, ll x) {
if (ql <= l && r <= qr) {
tree[rt].mx += x;
tree[rt].tag += x;
tree[rt].hmx = max(tree[rt].hmx, tree[rt].mx);
tree[rt].htag = max(tree[rt].htag, tree[rt].tag);
return;
}
pushdown(rt);
int mid = (l + r) >> 1;
if (ql <= mid) {
update(rt << 1, l, mid, ql, qr, x);
}
if (qr > mid) {
update(rt << 1 | 1, mid + 1, r, ql, qr, x);
}
pushup(rt);
}
ll query(int rt, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) {
return tree[rt].hmx;
}
pushdown(rt);
int mid = (l + r) >> 1;
ll res = 0;
if (ql <= mid) {
res = max(res, query(rt << 1, l, mid, ql, qr));
}
if (qr > mid) {
res = max(res, query(rt << 1 | 1, mid + 1, r, ql, qr));
}
return res;
}
void solve() {
scanf("%lld", &n);
for (int i = 1; i <= n; ++i) {
scanf("%lld", &a[i]);
lst[i] = pre[a[i] + maxn];
pre[a[i] + maxn] = i;
}
scanf("%lld", &m);
for (int i = 1; i <= m; ++i) {
int l, r;
scanf("%d%d", &l, &r);
qq[r].pb(make_pair(l, i));
}
for (int i = 1; i <= n; ++i) {
update(1, 1, n, lst[i] + 1, i, a[i]);
for (pii p : qq[i]) {
ans[p.scd] = query(1, 1, n, p.fst, i);
}
}
for (int i = 1; i <= m; ++i) {
printf("%lld\n", ans[i]);
}
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}