标签:
求一个区间的最大连续子序列,基本想法就是分治,这段子序列可能在区间的左半边,也可能在区间的右半边,也有可能是横跨区间中点,这样就是左子区间的最大后缀加上右子区间的最大前缀之和。
线段树维护三个信息:区间最大前缀、最大后缀、最大连续子区间的下标。
最大前缀可以通过递推来求:要么是左子区间的最大前缀和、要么是左子区间的和 加上 右子区间的最大前缀和
最大后缀和的递推类似。
递推之前要预处理整个序列的前缀和。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define MP make_pair 5 #define lch(o) (o*2) 6 #define rch(o) (o*2+1) 7 using namespace std; 8 9 typedef long long LL; 10 typedef pair<int, int> Interval; 11 const int maxn = 500000 + 10; 12 const int maxnode = 1000000 + 10; 13 14 LL prefix_sum[maxn]; 15 16 LL sum(int a, int b) { return prefix_sum[b] - prefix_sum[a-1]; } 17 18 LL sum(Interval p) { return sum(p.first, p.second); } 19 20 Interval better(Interval a, Interval b) 21 { 22 if(sum(a) != sum(b)) return sum(a) > sum(b) ? a : b; 23 return a < b ? a : b; //pair自带字典序 24 } 25 26 int qL, qR; //查询区间 27 28 struct IntervalTree 29 { 30 int max_prefix[maxnode], max_suffix[maxnode]; 31 Interval max_sub[maxnode]; 32 33 void build(int o, int L, int R) 34 { 35 if(L == R) { max_prefix[o] = max_suffix[o] = L; max_sub[o] = MP(L, L); } 36 else 37 { 38 int M = (L + R) >> 1; 39 int lc = lch(o), rc = rch(o); 40 build(lc, L, M); 41 build(rc, M+1, R); 42 43 //递推max_prefix 44 LL v1 = sum(L, max_prefix[lc]); 45 LL v2 = sum(L, max_prefix[rc]); 46 if(v1 == v2) max_prefix[o] = min(max_prefix[lc], max_prefix[rc]); 47 else max_prefix[o] = v1 > v2 ? max_prefix[lc] : max_prefix[rc]; 48 49 //递推max_suffix 50 v1 = sum(max_suffix[lc], R); 51 v2 = sum(max_suffix[rc], R); 52 if(v1 == v2) max_suffix[o] = min(max_suffix[lc], max_suffix[rc]); 53 else max_suffix[o] = v1 > v2 ? max_suffix[lc] : max_suffix[rc]; 54 55 //递推max_sub 56 max_sub[o] = better(max_sub[lc], max_sub[rc]); 57 max_sub[o] = better(max_sub[o], MP(max_suffix[lc], max_prefix[rc])); 58 } 59 } 60 61 Interval query_prefix(int o, int L, int R) 62 { 63 if(max_prefix[o] <= qR) return MP(L, max_prefix[o]); 64 int M = (L + R) >> 1; 65 int lc = lch(o), rc = rch(o); 66 if(qR <= M) return query_prefix(lc, L, M); 67 Interval i = query_prefix(rc, M+1, R); 68 i.first = L; 69 return better(i, MP(L, max_prefix[lc])); 70 } 71 72 Interval query_suffix(int o, int L, int R) 73 { 74 if(max_suffix[o] >= qL) return MP(max_suffix[o], R); 75 int M = (L + R) >> 1; 76 int lc = lch(o), rc = rch(o); 77 if(qL > M) return query_suffix(rc, M+1, R); 78 Interval i = query_suffix(lc, L, M); 79 i.second = R; 80 return better(i, MP(max_suffix[rc], R)); 81 } 82 83 Interval query(int o, int L, int R) 84 { 85 if(qL <= L && R <= qR) return max_sub[o]; 86 int M = (L + R) >> 1; 87 int lc = lch(o), rc = rch(o); 88 if(qR <= M) return query(lc, L, M); 89 if(qL > M) return query(rc, M+1, R); 90 Interval i1 = query_suffix(lc, L, M);//左子区间的最大后缀 91 Interval i2 = query_prefix(rc, M+1, R);//右子区间的最大前缀 92 Interval i3 = better(query(lc, L, M), query(rc, M+1, R));//两个子区间的最大连续和 93 return better(i3, MP(i1.first, i2.second)); 94 } 95 }tree; 96 97 int main() 98 { 99 //freopen("in.txt", "r", stdin); 100 101 int kase = 0, n, a, Q; 102 while(scanf("%d%d", &n, &Q) == 2) 103 { 104 prefix_sum[0] = 0; 105 for(int i = 1; i <= n; i++) { scanf("%d", &a); prefix_sum[i] = prefix_sum[i-1] + a; } 106 tree.build(1, 1, n); 107 printf("Case %d:\n", ++kase); 108 while(Q--) 109 { 110 int L, R; 111 scanf("%d%d", &L, &R); 112 qL = L; qR = R; 113 Interval ans = tree.query(1, 1, n); 114 printf("%d %d\n", ans.first, ans.second); 115 } 116 } 117 118 return 0; 119 }
UVa 1400 (线段树) "Ray, Pass me the dishes!"
标签:
原文地址:http://www.cnblogs.com/AOQNRMGYXLMV/p/4356495.html