我又来水数据结构了。
按照套路,线段树上要维护四个值$res, sum, suf, pre$,分别表示当前区间的最大子段和,总和,强制选右端点的最大子段和,强制选左端点的最大子段和,那么更新的时候就有:
inline void up(int p) { sum(p) = sum(lc) + sum(rc); suf(p) = max(suf(rc), sum(rc) + suf(lc)); pre(p) = max(pre(lc), sum(lc) + pre(rc)); res(p) = max(res(lc), res(rc), suf(lc) + pre(rc)); }
注意查询的时候返回空结点的$suf,pre,res$都是$-inf$。
如果询问$xa, ya, xb, yb$满足$ya < xb$,那么答案就为$sum(ya, xb) + max(0, suf(xa, ya - 1)) + max(0, pre(xb + 1, yb))$;如果不满足,那么答案在$res(xb, ya)$、$pre(ya + 1, yb) + suf(xb, ya)$、$pre(xb, ya) + suf(xa, xb - 1)$、$sum(xb, ya) + max(0, suf(xa, xb - 1)) + max(0, pre(ya + 1, yb))$取个最大。
画个图理解一下就好啦。
时间复杂度为$O(Tnlogn)$,虽然常数很大,但是跑个$10000$完全没问题。
Code:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <cstdio> #include <cstring> using namespace std; const int N = 1e4 + 5; const int inf = 1 << 30; int testCase, n, qn, a[N]; inline void read(int &X) { X = 0; char ch = 0; int op = 1; for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') op = -1; for(; ch >= '0' && ch <= '9'; ch = getchar()) X = (X << 3) + (X << 1) + ch - 48; X *= op; } inline int max(int x, int y) { return x > y ? x : y; } inline int max(int x, int y, int z) { return max(x, max(y, z)); } inline void chkMax(int &x, int y) { if(y > x) x = y; } namespace SegT { struct Node { int lc, rc, res, suf, pre, sum; inline void init() { res = suf = pre = -inf, sum = 0; } } s[N << 2]; #define lc p << 1 #define rc p << 1 | 1 #define res(p) s[p].res #define suf(p) s[p].suf #define pre(p) s[p].pre #define sum(p) s[p].sum #define mid ((l + r) >> 1) inline void up(int p) { sum(p) = sum(lc) + sum(rc); suf(p) = max(suf(rc), sum(rc) + suf(lc)); pre(p) = max(pre(lc), sum(lc) + pre(rc)); res(p) = max(res(lc), res(rc), suf(lc) + pre(rc)); } void build(int p, int l, int r) { if(l == r) { sum(p) = res(p) = suf(p) = pre(p) = a[l]; return; } build(lc, l, mid); build(rc, mid + 1, r); up(p); } Node query(int p, int l, int r, int x, int y) { if(x > y) return (Node) {0, 0, -inf, -inf, -inf, 0}; if(x <= l && y >= r) return s[p]; Node ln, rn, res; ln.init(), rn.init(), res.init(); if(x <= mid) ln = query(lc, l, mid, x, y); if(y > mid) rn = query(rc, mid + 1, r, x, y); res.sum = ln.sum + rn.sum; res.suf = max(rn.suf, ln.suf + rn.sum); res.pre = max(ln.pre, rn.pre + ln.sum); res.res = max(ln.res, rn.res, ln.suf + rn.pre); return res; } } using namespace SegT; inline void solve(int xa, int ya, int xb, int yb) { int res; if(ya < xb) { res = query(1, 1, n, ya, xb).sum; res += max(0, query(1, 1, n, xa, ya - 1).suf); res += max(0, query(1, 1, n, xb + 1, yb).pre); } else { res = query(1, 1, n, xb, ya).res; chkMax(res, query(1, 1, n, ya + 1, yb).pre + query(1, 1, n, xb, ya).suf); chkMax(res, query(1, 1, n, xa, xb - 1).suf + query(1, 1, n, xb, ya).pre); chkMax(res, query(1, 1, n, xb, ya).sum + max(0, query(1, 1, n, xa, xb - 1).suf) + max(0, query(1, 1, n, ya + 1, yb).pre)); } printf("%d\n", res); } int main() { for(read(testCase); testCase--; ) { read(n); for(int i = 1; i <= n; i++) read(a[i]); build(1, 1, n); read(qn); for(int xa, ya, xb, yb; qn--; ) { read(xa), read(ya), read(xb), read(yb); solve(xa, ya, xb, yb); } } return 0; }