题目链接:https://vjudge.net/contest/146667#problem/C
题意:动态的求一个区间的最大连续和。
分析:
看上去可以RMQ去做,但是,当分成两个部分,原来的部分的解可能是跨越这两个区间的。原问题的解不能通过RMQ分成的两个部分的解而得到。
线段树:
线段树很早之前就有学习,那个时候只会套模板,而这个题目几乎就是线段树的一个理解应用。
就在刚刚之前提到的那个问题一样,可以利用线段树维护3个信息:
max_prefix(最大前缀和的标号)
max_suffix(最大后缀和的标号)
有了这两个信息,就可以跨区间找到丢失的信息了。
还有一个就是结果 max_sub(最大连续和的标号,其中是一个pair类型)
建树时:
建好左右子树后,递推max_prefix,max_suffix,这两个都不用跨区间,递推max_sub需要跨区间。
这里没有更新操作。
询问时:
同样分三种情况,左半边,右半边,跨区间。
跨区间这里,就用到了我们之前维护的最大前缀和标号,和最大后缀和标号。
那么如何得到最大前缀和标号,和最大后缀和标号呢?
同理:也是分区间查找,但是右半部分的左边的标号必须是L,左半部分简单一点,就是左孩子的最大前缀和的标号。
同理最大后缀和的标号。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 500000 + 10; 6 const int maxnode = 1000000 + 10; 7 typedef long long LL; 8 typedef pair<int,int> Interval; 9 10 LL prefix_sum[maxn]; 11 12 //求区间和 13 LL sum(int L,int R) { 14 return prefix_sum[R] - prefix_sum[L-1]; 15 } 16 17 //求区间和 18 LL sum(Interval p) { 19 return sum(p.first,p.second); 20 } 21 22 Interval better(Interval a,Interval b) { 23 if(sum(a)!=sum(b)) return sum(a) > sum(b) ? a : b; 24 return a<b? a:b; 25 } 26 27 int qL,qR; 28 29 struct IntervalTree 30 { 31 int max_prefix[maxnode]; //最大前缀和对应的标号 32 int max_suffix[maxnode]; //最大后缀和对应的标号 33 Interval max_sub[maxnode]; //最大连续和对应的起点和终点 34 35 void build(int o,int L,int R) 36 { 37 if(L==R) 38 { 39 max_prefix[o] = max_suffix[o] = L; 40 max_sub[o] = make_pair(L,L); 41 } 42 else 43 { 44 int M = L+(R-L)/2; 45 int lc = o*2,rc = o*2+1; 46 build(lc,L,M); 47 build(rc,M+1,R); 48 49 //递推最大前缀和 50 LL v1 = sum(L,max_prefix[lc]); 51 LL v2 = sum(L,max_prefix[rc]); 52 if(v1==v2) max_prefix[o] = min(max_prefix[lc],max_prefix[rc]); 53 else max_prefix[o] = v1 > v2 ? max_prefix[lc] : max_prefix[rc]; 54 55 //递推最大后缀和 56 v1 = sum(max_suffix[lc],R); 57 v2 = sum(max_suffix[rc],R); 58 if(v1==v2) max_suffix[o] = min(max_suffix[lc],max_suffix[rc]); 59 else max_suffix[o] = v1 > v2 ? max_suffix[lc] : max_suffix[rc]; 60 61 //递推最大连续和 62 max_sub[o] = better(max_sub[lc],max_sub[rc]); 63 max_sub[o] = better(max_sub[o],make_pair(max_suffix[lc],max_prefix[rc])); 64 } 65 } 66 67 //求最大前缀和的那个区间 68 Interval query_prefix(int o,int L,int R) 69 { 70 if(max_prefix[o]<=qR) return make_pair(L,max_prefix[o]); 71 int M = L + (R-L)/2; 72 int lc = o*2,rc = o*2 + 1; 73 if(qR<=M) return query_prefix(lc,L,M); 74 Interval i = query_prefix(rc,M+1,R); 75 i.first = L; 76 return better(i,make_pair(L,max_prefix[lc])); 77 } 78 79 80 Interval query_suffix(int o,int L,int R) 81 { 82 if(max_suffix[o]>=qL) return make_pair(max_suffix[o],R); 83 int M = L + (R-L) /2; 84 int lc = o*2,rc = o*2+1; 85 if(qL>M) return query_suffix(rc,M+1,R); 86 Interval i = query_suffix(lc,L,M); 87 i.second = R; 88 return better(i,make_pair(max_suffix[rc],R)); 89 90 } 91 92 Interval query(int o,int L,int R) 93 { 94 if(qL<=L&&R<=qR) return max_sub[o]; 95 int M = L + (R - L) /2; 96 int lc = o*2,rc = o*2+1; 97 if(qR<=M) return query(lc,L,M); 98 if(qL>M) return query(rc,M+1,R); 99 Interval i1 = query_prefix(rc,M+1,R); 100 Interval i2 = query_suffix(lc,L,M); 101 Interval i3 = better(query(lc,L,M),query(rc,M+1,R)); //分开 102 return better(make_pair(i2.first,i1.second),i3); //跨区间 103 } 104 105 }; 106 107 IntervalTree tree; 108 109 int main() 110 { 111 int n,q,a; 112 int cases = 1; 113 while(scanf("%d%d",&n,&q)==2) 114 { 115 prefix_sum[0] = 0; 116 for(int i=0; i<n; i++) 117 { 118 scanf("%d",&a); 119 prefix_sum[i+1] = prefix_sum[i] + a; 120 } 121 tree.build(1,1,n); 122 printf("Case %d: ",cases++); 123 124 while(q--) { 125 int L,R; 126 scanf("%d%d",&L,&R); 127 qL = L; 128 qR = R; 129 Interval ans = tree.query(1,1,n); 130 printf("%d %d ",ans.first,ans.second); 131 } 132 133 134 } 135 136 return 0; 137 }