3981 动态最大子段和

Posted whymhe

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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。

我不会告诉你数据里有样例

 
 
//题意:询问一段区间的最大子序列的值。
//就是GSS1多开点空间然后开longlong 

//做法:维护四个值:包含当前区间左端点的最大子区间LM,包含当前区间右端点的最大子区间RM、当前区间的最大子区间M, 当前区间的区间和S 
//tree[root].maxn=max(tree[root<<1].maxn,max(tree[root<<1|1].maxn,tree[root<<1].rmaxn+tree[root<<1|1].lmaxn));
//    tree[root].lmaxn=max(tree[root<<1].lmaxn,tree[root<<1].sum+tree[root<<1|1].lmaxn);
//    tree[root].rmaxn=max(tree[root<<1|1].rmaxn,tree[root<<1|1].sum+tree[root<<1].rmaxn);
//    tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum;
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

const int N=2e5+5;

int n,m,l,r;
long long L,R,M,S;
struct Tree
{
    int l,r,mid;
    long long sum,lmaxn,rmaxn,maxn;
}tree[N<<2];

inline long long read()
{
    char c=getchar();long long num=0,f=1;
    for(;!isdigit(c);c=getchar())
        f=c==-?-1:f;
    for(;isdigit(c);c=getchar())
        num=num*10+c-0;
    return num*f;
}

inline void pushup(int root)
{
    tree[root].maxn=max(tree[root<<1].maxn,max(tree[root<<1|1].maxn,tree[root<<1].rmaxn+tree[root<<1|1].lmaxn));
    tree[root].lmaxn=max(tree[root<<1].lmaxn,tree[root<<1].sum+tree[root<<1|1].lmaxn);
    tree[root].rmaxn=max(tree[root<<1|1].rmaxn,tree[root<<1|1].sum+tree[root<<1].rmaxn);
    tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum;
}

void build(int root,int l,int r)
{
    tree[root].l=l,tree[root].r=r,tree[root].mid=l+r>>1;
    if(l==r)
    {
        tree[root].sum=tree[root].maxn=tree[root].rmaxn=tree[root].lmaxn=read();
        return;
    }
    build(root<<1,l,tree[root].mid);
    build(root<<1|1,tree[root].mid+1,r);
    pushup(root);
}

void query(int root,int l,int r,long long &L,long long &R,long long &M,long long &S)
{
    if(l<=tree[root].l&&tree[root].r<=r)
    {
        L=tree[root].lmaxn,
        R=tree[root].rmaxn,
        M=tree[root].maxn,
        S=tree[root].sum;
        return;
    }
    if(tree[root].mid>=r)
    {
        query(root<<1,l,r,L,R,M,S);
    }
    else if(tree[root].mid<l)
    {
        query(root<<1|1,l,r,L,R,M,S);
    }
    else
    {
        long long lL=0,lR=0,lM=0,lS=0,rL=0,rR=0,rM=0,rS=0;
        query(root<<1,l,tree[root].mid,lL,lR,lM,lS);
        query(root<<1|1,tree[root].mid+1,r,rL,rR,rM,rS);
        L=max(lL,lS+rL);
        R=max(rR,rS+lR);
        M=max(lR+rL,max(lM,rM));
        S=lS+rS;
    }
}

int main()
{
    n=read();
    build(1,1,n);
    m=read();
    for(int i=1;i<=m;++i)
    {
        l=read(),r=read();
        query(1,l,r,L,R,M,S);
        printf("%lld\n",M);
    }
    return 0;
}

 

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

3981 动态最大子段和

CODEVS 3981(求最大子段和+线段树)

动态规划 ------最大子段和

动态规划 最大子段和

动态规划入门 TYVJ1305 最大子段和(环状)

动态规划入门 P1115 最大子段和(链状)