codevs3981动态最大子段和(线段树)

3981 动态最大子段和

 时间限制: 1 s
 空间限制: 128000 KB
 题目等级 : 钻石 Diamond
 
 
题目描述  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。

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

 
/*
线段树区间操作GSS 
一段长的区间的 GSS 有三种情况:
1 完全在左子区间
2 完全在右子区间
3 横跨左右区间
前两种情况可使用子区间的 GSS,但如何处理第三种情况?
注意到我们可以把区间拆成两部分,这两部分是不相关的。
所以我们需要维护一个区间的“最大左子段和”和“最大右子段和”。
gss = MAX{l.gss,r.gss,l.rgss + r.lgss}
由 GSS 一直推下来,对于每个节点,我们一共需要设计4个状态。 
1 GSS:最大子段和
2 LGSS:最大左子段和
3 RGSS:最大右子段和
4 SUM:整段和
这里我用了结构体存储(元元真厉害啊!) 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define maxn 2000010

using namespace std;
ll n,a[maxn],q,x,y,ans;
struct node{
    ll l,r,dis,mx,lmx,rmx;
}tre[maxn>>2];

ll init()
{
    ll x=0,f=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

void build(int now,ll l,ll r)
{
    tre[now].l=l;tre[now].r=r;
    if(l==r)
    {
        tre[now].dis=init();
        tre[now].lmx=tre[now].rmx=tre[now].mx=tre[now].dis;
        return ;
    }
    ll mid=(l+r)>>1;
    build(now<<1,l,mid);
    build(now<<1|1,mid+1,r);
    //下面是重点之一,要注意。 
    tre[now].lmx=max(tre[now<<1].lmx,tre[now<<1].dis+tre[now<<1|1].lmx);
    tre[now].rmx=max(tre[now<<1|1].rmx,tre[now<<1|1].dis+tre[now<<1].rmx);
    tre[now].mx=max(tre[now<<1].rmx+tre[now<<1|1].lmx,max(tre[now<<1].mx,tre[now<<1|1].mx));
    tre[now].dis=tre[now<<1].dis+tre[now<<1|1].dis;
}

node query(int now,ll l,ll r)
{
    node ans;
    if(l==tre[now].l&&r==tre[now].r) return tre[now];
    ll mid=(tre[now].l+tre[now].r)>>1;
    if(l>mid) return query(now<<1|1,l,r);
    else if(r<=mid) return query(now<<1,l,r);
    else//就是这里咋也不会写,递归找边界思路不清晰 
    {
        node lch=query(now<<1,l,mid);
        node rch=query(now<<1|1,mid+1,r);
        ans.lmx=max(lch.lmx,lch.dis+rch.lmx);
        ans.rmx=max(rch.rmx,rch.dis+lch.rmx);
        ans.mx=max(max(lch.mx,rch.mx),lch.rmx+rch.lmx);
    }
    return ans;
}
int main()
{
    n=init();
    build(1,1,n);
    q=init();
    for(int i=1;i<=q;i++)
    {
        x=init();y=init();
        printf("%lld\n",query(1,x,y).mx);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/L-Memory/p/6369027.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值