codevs 3981 动态最大子段和(线段树)

Posted l999q

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了codevs 3981 动态最大子段和(线段树)相关的知识,希望对你有一定的参考价值。

题目传送门:codevs 3981 动态最大子段和 

 

题目描述 Description

题目还是简单一点好... 

有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

数据范围及提示 Data Size & Hint

对于50%的数据,q*n<=10000000。

对于100%的数据,1<=n<=200000,1<=q<=200000。

a[1]~a[n]在int范围内,但是答案可能超出int范围。

数据保证1<=l<=r<=n。

空间128M,时间1s。

 

题目大意:

  求解区间 a[l]~a[r] 的最大子段和

 

解题思路:

  用线段树维护区间最大值。开几个变量存区间和sum,完全在左区间的最大值max_l,完全在右区间的最大值max_r,跨左右区间的最大值max。

 

技术分享图片
 1 #include <bits/stdc++.h>
 2 #define lson rt<<1,l,mid
 3 #define rson rt<<1|1,mid+1,r
 4 using namespace std;
 5 const int N = 200000 + 10;
 6 typedef long long int ll;
 7 struct node
 8 {
 9     int l,r;
10     ll max_,max_l,max_r,sum;
11 } a[N<<2];
12 int n,q,x,y;
13 ll ans;
14 void up(int rt)
15 {
16     a[rt].max_=max(max(a[rt<<1].max_,a[rt<<1|1].max_),a[rt<<1].max_r+a[rt<<1|1].max_l);
17     a[rt].max_l=max(a[rt<<1].max_l,a[rt<<1].sum+a[rt<<1|1].max_l);
18     a[rt].max_r=max(a[rt<<1|1].max_r,a[rt<<1|1].sum+a[rt<<1].max_r);
19     a[rt].sum=a[rt<<1].sum+a[rt<<1|1].sum;
20 }
21 void build(int rt,int l,int r)
22 {
23     a[rt].l=l,a[rt].r=r;
24     if (l==r)
25     {
26         scanf("%lld",&a[rt].max_);
27         a[rt].max_l=a[rt].max_r=a[rt].sum=a[rt].max_;
28         return ;
29     }
30     int mid = (l+r)>>1;
31     build(lson);
32     build(rson);
33     up(rt);
34 }
35 void query(int rt,int L,int R,ll &ans,ll &ansl,ll &ansr)
36 {
37     if (L<=a[rt].l&&a[rt].r<=R)
38     {
39         ans=a[rt].max_;
40         ansl=a[rt].max_l;
41         ansr=a[rt].max_r;
42         return ;
43     }
44     int mid=(a[rt].l+a[rt].r)>>1;
45     if (mid>=R) query(rt<<1,L,R,ans,ansl,ansr);
46     else if (mid<L) query(rt<<1|1,L,R,ans,ansl,ansr);
47     else
48     {
49         ll lans=0,lansl=0,lansr=0,rans=0,ransl=0,ransr=0;
50         query(rt<<1,L,R,lans,lansl,lansr);
51         query(rt<<1|1,L,R,rans,ransl,ransr);
52         ans=max(max(lans,rans),lansr+ransl);
53         ansl=max(lansl,ransl+a[rt<<1].sum);
54         ansr=max(ransr,lansr+a[rt<<1|1].sum);
55     }
56 }
57 int main()
58 {
59     scanf("%d",&n);
60     build(1,1,n);
61     for ( scanf("%d",&q); q; q--)
62     {
63         scanf("%d%d",&x,&y);
64         ll ans=0,ansl=0,ansr=0;
65         query(1,x,y,ans,ansl,ansr);
66         printf("%lld
",ans);
67     }
68     return 0;
69 }
View Code

 










以上是关于codevs 3981 动态最大子段和(线段树)的主要内容,如果未能解决你的问题,请参考以下文章

codevs 3981 动态最大子段和

线段树复习

3981 动态最大子段和

线段树维护区间最大子段和

Codeforces 1107G 线段树最大子段和 + 单调栈

p1115 最大子段和(线段树)