题意:
给定一个序列和m个询问, 要求求出一个区间内最大连续子段和, 并且相同的数只能算一次。
思路:
把询问离线, 按右端点排序,从小到大扫描询问, 假设当前询问的右端点是r, 用线段树维护4个值:
mx_s: 左端点为ll,右端点在[l,r]的最大连续子段和(也就是最优的情况)。
s:左端点为ll, 到r的区间和。
mx_add: 区间的最优懒惰标记。
add: 区间的所有懒惰标记。
更新第i个数时候, 把pre[a[i]] + 1 ~ i都加上a[i]。
查询的时候就是l~r的mx_s
重点在push_up和push_down...
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <iomanip>
#include <map>
#include <set>
#include <algorithm>
using namespace std;
#define N 100020
#define mod 1000000007
#define mxe 2000020
#define MP make_pair
#define PB push_back
#define LL long long
#define ULL unsigned LL
#define inf 0x3f3f3f3f
#define ls (i << 1)
#define rs (ls | 1)
#define md ((ll + rr) >> 1)
#define lson ll, md, ls
#define rson md + 1, rr, rs
#pragma comment(linker, "/STACK:1024000000,1024000000")
int n, m;
int s[N<<2], mx_s[N<<2], add[N<<2], mx_add[N<<2];
int a[N], pre[N*2];
struct query {
int l, r, ans;
}p[N];
int id[N];
bool cmp(int i, int j) {
return p[i].r < p[j].r;
}
void add_val(int i, int v) {
add[i] += v;
mx_add[i] = max(mx_add[i], add[i]);
s[i] += v;
mx_s[i] = max(mx_s[i], s[i]);
}
void push_down(int i) {
mx_add[ls] = max(mx_add[ls], add[ls] + mx_add[i]);
add[ls] += add[i];
mx_s[ls] = max(mx_s[ls], s[ls] + mx_add[i]);
s[ls] += add[i];
mx_add[rs] = max(mx_add[rs], add[rs] + mx_add[i]);
add[rs] += add[i];
mx_s[rs] = max(mx_s[rs], s[rs] + mx_add[i]);
s[rs] += add[i];
add[i] = mx_add[i] = 0;
}
void push_up(int i) {
mx_s[i] = max(mx_s[ls], mx_s[rs]);
s[i] = max(s[ls], s[rs]);
}
void update(int l, int r, int v, int ll, int rr, int i) {
if(ll == l && rr == r) {
add_val(i, v);
return;
}
push_down(i);
if(r <= md) update(l, r, v, lson);
else if(l > md) update(l, r, v, rson);
else
update(l, md, v, lson), update(md + 1, r, v, rson);
push_up(i);
}
int query(int l, int r, int ll, int rr, int i) {
if(ll == l && rr == r) return mx_s[i];
push_down(i);
if(r <= md) return query(l, r, lson);
if(l > md) return query(l, r, rson);
return max(query(l, md, lson), query(md + 1, r, rson));
}
int main() {
// freopen("tt.txt", "r", stdin);
while(scanf("%d", &n) != EOF) {
for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
scanf("%d", &m);
for(int i = 1; i <= m; ++i) {
scanf("%d%d", &p[i].l, &p[i].r);
id[i] = i;
}
sort(id + 1, id + m + 1, cmp);
memset(s, 0, sizeof s);
memset(mx_s, 0, sizeof mx_s);
memset(add, 0, sizeof add);
memset(mx_add, 0, sizeof mx_add);
memset(pre, 0, sizeof pre);
int j = 1;
for(int i = 1; i <= m; ++i) {
int u = id[i];
while(j <= n && j <= p[u].r) {
update(pre[a[j]+N] + 1, j, a[j], 1, n, 1);
pre[a[j]+N] = j;
++j;
}
p[u].ans = query(p[u].l, p[u].r, 1, n, 1);
}
for(int i = 1; i <= m; ++i)
printf("%d\n", p[i].ans);
}
return 0;
}