question:
有n個數,a[1]到a[n]。
接下來q次查詢,每次動態指定兩個數l,r,求a[l]到a[r]的最大子段和。
子段的意思是連續非空區間。
輸入描述
Input Description
第一行一個數n。
第二行n個數a[1]~a[n]。
第三行一個數q。
以下q行每行兩個數l和r。
輸出描述
Output Description
q行,每行一個數,表示a[l]到a[r]的最大子段和。
樣例輸入
Sample Input
7
2 3 -233 233 -23 -2 233
4
1 7
5 6
2 5
2 3
樣例輸出
Sample Output
441
-2
233
3
高效完成這個問題,可以用線段樹進行區間動態查詢最大字段和
最大字段和
線段樹實現
線段樹維護:
1. 區間最大字段和
2. 從該區間的左端點開始的最大字段和(一定包括該區間左端點)
3. 從該區間的右端點開始的最大字段和(同理一定包括該區間右端點)
最大字段和分布
1. 完全的包含於做區間
2. 完全的包含於右區間
3. 包含於左右區間
維護的2,3主要是用於處理分布為3的情況
合並:很好理解
查詢:
當查詢區間完全處於當前區間的左側
查詢當前區間的左兒子
當查詢區間完全處於當前區間的右側
查詢當前區間的由兒子
否則說明查詢區間包含當前區間的mid
將ans等置為0,從當前區間的左右兒子開始查詢
會在3個黑圈處執行區間完全包含
從左到右依次編號1,2,3
會在1,2號return后進行一次ans, l_ans, r_ans 的賦max值
會在3好return后進行行一次ans, l_ans, r_ans 的賦max值
當遞歸到2,3節點時(注意這里是節點),進行一次
ans = max(max(L_ans, R_ans), L_rans + R_lans); l_ans = max(l_ans, T[jd << 1].w + R_lans); r_ans = max(r_ans, T[jd << 1 | 1].w + L_rans);
結束后ans即為answer
#include <iostream> #include <cstdio> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; const int N = 4e6 + 1; #define LL long long #define zero 0 struct Node{ int l, r, w, max, l_max, r_max; }; Node T[N]; int n, m; struct R{ inline int reint(){ int x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9'){ if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } inline LL rell(){ LL x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9'){ if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } }re; void un(int jd){ T[jd].max = max(max(T[jd << 1].max, T[jd << 1 | 1].max), T[jd << 1].r_max + T[jd << 1 | 1].l_max); T[jd].l_max = max(T[jd << 1].l_max, T[jd << 1].w + T[jd << 1 | 1].l_max); T[jd].r_max = max(T[jd << 1 | 1].r_max, T[jd << 1 | 1].w + T[jd << 1].r_max); T[jd].w = T[jd << 1].w + T[jd << 1 | 1].w; return ; } void build_tree(int l, int r, int jd){ T[jd].l = l; T[jd].r = r; if(l == r){ T[jd].w = re.reint(); T[jd].l_max = T[jd].r_max = T[jd].max = T[jd].w; return ; } int mid = (l + r) >> 1; build_tree(l, mid, jd << 1); build_tree(mid + 1, r, jd << 1 | 1); un(jd); } void Q_ask(int l, int r, int jd, int x, int y, LL & ans, LL & l_ans, LL & r_ans){ if(x <= l && r <= y){ ans = T[jd].max; l_ans = T[jd].l_max; r_ans = T[jd].r_max; return ; } int mid = (l + r) >> 1; if(y <= mid) Q_ask(l, mid, jd << 1, x, y, ans, l_ans, r_ans); else if(x > mid) Q_ask(mid + 1, r, jd << 1 | 1, x, y, ans, l_ans, r_ans); else{ LL L_ans,L_lans, L_rans, R_ans, R_lans, R_rans; L_ans = L_lans = L_rans = R_ans = R_lans = R_rans = zero; Q_ask(l, mid, jd << 1, x, y, L_ans, L_lans, L_rans); Q_ask(mid + 1, r, jd << 1 | 1, x, y, R_ans, R_lans, R_rans); ans = max(max(L_ans, R_ans), L_rans + R_lans); l_ans = max(l_ans, T[jd << 1].w + R_lans); r_ans = max(r_ans, T[jd << 1 | 1].w + L_rans); } } int main(){ n = re.reint(); build_tree(1, n, 1); m = re.reint(); for(int i = 1; i <= m; i ++) { int x = re.reint(); int y = re.reint(); LL ans, l_ans, r_ans; ans = l_ans = r_ans = zero; Q_ask(1, n, 1, x, y, ans, l_ans, r_ans); printf("%lld\n", ans); } return 0; }