题意:
给定一个长为 n 的数组 a,有 q 次询问,每次询问区间 [ L, R ] 的最大子段和(相同元素只计一次)。(n, q, <= 1e5)
链接:
https://vjudge.net/problem/SPOJ-GSS2
解题思路:
考虑离线,每次遇到右端点时统计答案。对于当前元素 a[ i ],只对 last[ a[ i ] ] + 1 到 i 这一段增加 a[ i ],则对于询问 [ l, i ],答案就是区间内的历史最值。
线段树维护历史最值,记当前最值为 mx,历史最值为 pmx,当前标记为 add,历史最大标记为 padd(add 下推前的最值),则历史最值的 pushdown 操作为:
当前最值及标记照常维护即可。
参考代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define sz(a) ((int)a.size())
#define mem(a, b) memset(a, b, sizeof a)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e5 + 5;
const int maxm = 2e6 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
vector<pii> G[maxn];
ll mx[maxn << 2], add[maxn << 2];
ll pmx[maxn << 2], padd[maxn << 2];
int a[maxn], ri[maxn], last[maxn << 1];
ll ans[maxn];
int n, q;
void build(int l, int r, int rt){
padd[rt] = add[rt] = pmx[rt] = mx[rt] = 0;
if(l == r) return;
int mid = gmid;
build(l, mid, lson);
build(mid + 1, r, rson);
}
void pushUp(int rt){
pmx[rt] = max(pmx[lson], pmx[rson]);
mx[rt] = max(mx[lson], mx[rson]);
}
void pushDown(int rt){
padd[lson] = max(padd[lson], add[lson] + padd[rt]);
padd[rson] = max(padd[rson], add[rson] + padd[rt]);
pmx[lson] = max(pmx[lson], mx[lson] + padd[rt]);
pmx[rson] = max(pmx[rson], mx[rson] + padd[rt]);
add[lson] += add[rt], add[rson] += add[rt];
mx[lson] += add[rt], mx[rson] += add[rt];
padd[rt] = add[rt] = 0;
}
void update(int l, int r, int rt, int L, int R, int val){
if(l >= L && r <= R){
padd[rt] = max(padd[rt], add[rt] += val);
pmx[rt] = max(pmx[rt], mx[rt] += val);
return;
}
int mid = gmid;
pushDown(rt);
if(L <= mid) update(l, mid, lson, L, R, val);
if(R > mid) update(mid + 1, r, rson, L, R, val);
pushUp(rt);
}
ll query(int l, int r, int rt, int L, int R){
if(l >= L && r <= R) return pmx[rt];
int mid = gmid; ll ret = 0;
pushDown(rt);
if(L <= mid) ret = max(ret, query(l, mid, lson, L, R));
if(R > mid) ret = max(ret, query(mid + 1, r, rson, L, R));
return ret;
}
int main(){
// ios::sync_with_stdio(0); cin.tie(0);
while(scanf("%d", &n) != EOF){
for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
scanf("%d", &q);
for(int i = 1; i <= q; ++i){
int l; scanf("%d%d", &l, &ri[i]);
G[ri[i]].pb({l, i});
}
build(1, n, 1);
for(int i = 1; i <= n; ++i){
update(1, n, 1, last[a[i] + maxn] + 1, i, a[i]);
last[a[i] + maxn] = i;
for(int j = 0; j < sz(G[i]); ++j){
int l = G[i][j].first, p = G[i][j].second;
ans[p] = query(1, n, 1, l, i);
}
}
for(int i = 1; i <= q; ++i) printf("%lld\n", ans[i]);
for(int i = 1; i <= n; ++i) last[a[i] + maxn] = 0;
for(int i = 1; i <= q; ++i) G[ri[i]].clear();
}
return 0;
}