知识点:线段树
这个也是个水紫,就是紫题里面比较简单的甚至降到蓝题都可以,还是线段树维护最大连续子列和问题,这回两个端点变成了区间,其实并没有变难多少,就是分类讨论就行了,右边左端点大于左边右端点,这个情况比较简单,但是我一开始也是写的很麻烦,中间的不在两个区间的数都是要的,所以要求和,然后拼接上两边挨着端点的最大就行,第二个情况稍微复杂一点,但是也还好,可以分成3个区间,如果都存在的话,那么就是4中情况,两个点都在中间,一个在中间一个在左边区间,一个在中间一个在右边区间,一个在左边一个在右边,就是这个4种情况里面取最大值就行了
#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 5;
struct tree {
int l, r;
int sum, m, lm, rm;
};
int a[N];
tree t[N * 4];
void pushup(int p) {
int p1 = p * 2, p2 = p * 2 + 1;
t[p].sum = t[p1].sum + t[p2].sum;
t[p].m = max(max(t[p1].m, t[p2].m), t[p1].rm + t[p2].lm);
t[p].lm = max(t[p1].lm, t[p1].sum + t[p2].lm);
t[p].rm = max(t[p2].rm, t[p2].sum + t[p1].rm);
}
void build(int p, int l, int r) {
t[p].l = l; t[p].r = r;
if (l == r) {
t[p].sum = t[p].m = t[p].lm = t[p].rm = a[l];
return;
}
int mid = (l + r) / 2;
build(p * 2, l, mid);
build(p * 2 + 1, mid + 1, r);
pushup(p);
}
tree query(int p, int l, int r) {
if (l <= t[p].l && r >= t[p].r) return t[p];
int mid = (t[p].l + t[p].r) / 2;
if (l > mid) return query(p * 2 + 1, l, r);
if (r <= mid) return query(p * 2, l, r);
tree res, t1 = query(p * 2, l, r), t2 = query(p * 2 + 1, l, r);
res.sum = t1.sum + t2.sum;
res.m = max(max(t1.m, t2.m), t1.rm + t2.lm);
res.lm = max(t1.lm, t1.sum + t2.lm);
res.rm = max(t2.rm, t2.sum + t1.rm);
return res;
}
int main() {
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
build(1, 1, n);
int m;
cin >> m;
while (m--) {
int x1, y1, x2, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
int ans;
if (x2 > y1) {
if (x2 - y1 == 1) ans = 0;
else ans = query(1, y1 + 1, x2 - 1).sum;
ans += query(1, x1, y1).rm + query(1, x2, y2).lm;
} else {
ans = query(1, x2, y1).m;
tree tmp = query(1, x2, y1);
if (y2 > y1) ans = max(ans, tmp.rm + query(1, y1 + 1, y2).lm);
if (x1 < x2) ans = max(ans, tmp.lm + query(1, x1, x2 - 1).rm);
if (y2 > y1 && x1 < x2) ans = max(ans, tmp.sum + query(1, y1 + 1, y2).lm + query(1, x1, x2 - 1).rm);
}
printf("%d\n", ans);
}
}
return 0;
}