LA 3938 动态最大连续和

题目链接: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:\n",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\n",ans.first,ans.second);
131         }
132 
133 
134     }
135 
136     return 0;
137 }

 

转载于:https://www.cnblogs.com/TreeDream/p/6308520.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值