UVa 1400 (线段树) "Ray, Pass me the dishes!"

求一个区间的最大连续子序列,基本想法就是分治,这段子序列可能在区间的左半边,也可能在区间的右半边,也有可能是横跨区间中点,这样就是左子区间的最大后缀加上右子区间的最大前缀之和。

线段树维护三个信息:区间最大前缀、最大后缀、最大连续子区间的下标。

最大前缀可以通过递推来求:要么是左子区间的最大前缀和、要么是左子区间的和 加上 右子区间的最大前缀和

最大后缀和的递推类似。

递推之前要预处理整个序列的前缀和。

  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:
", ++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
", ans.first, ans.second);
115         }
116     }
117 
118     return 0;
119 }
代码君
原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4356495.html