Can you answer these queries III SPOJ - GSS3(线段树求区间最大子段和)

You are given a sequence A of N (N <= 50000) integers between -10000 and 10000. On this sequence you have to apply M (M <= 50000) operations:
modify the i-th element in the sequence or for given x y print max{Ai + Ai+1 + … + Aj | x<=i<=j<=y }.

Input
The first line of input contains an integer N. The following line contains N integers, representing the sequence A1…AN.
The third line contains an integer M. The next M lines contain the operations in following form:
0 x y: modify Ax into y (|y|<=10000).
1 x y: print max{Ai + Ai+1 + … + Aj | x<=i<=j<=y }.
Output
For each query, print an integer as the problem required.

Example
Input:
4
1 2 3 4
4
1 1 3
0 3 -3
1 2 4
1 3 3

Output:
6
4
-3
求区间最大子段和。
学过求整个区间最大子段和的问题,O(n)的时间复杂度扫过一遍就行。
但是求一段区间内的就很麻烦。我们学过的数据结构就是来优化算法的。线段树就派上用场了。
(真的很佩服把这些算法想出来的人)
线段树维护四个值。
1.区间靠近左端点的最大子段和值。
2.区间靠近右端点的最大子段和值。
3.整个区间的总值。
4.整个区间的最大子段和值。
①维护靠近左端点的最大子段和值,有两个来源:左儿子的lmax,左儿子的msum+右儿子的lmax。
②维护靠近右端点的最大子段和值,有两个来源,右儿子的rmax,右儿子的msum+左儿子的rmax。
③维护整个区间的最大子段和值,有三个来源,左儿子的msum,右儿子的msum,左儿子的rmax+右儿子的lmax。
④维护整个区间的总值。
在这里插入图片描述
代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;

const int maxx=1e5+100;
struct node{
	int l;
	int r;
	int msum;
	int lsum;
	int rsum;
	int sum;
}p[maxx<<2];
int a[maxx];
int n,m,L,R,ans;

inline int read() 
{
    char ch = getchar(); int x = 0, f = 1;
    while(ch < '0' || ch > '9') {
        if(ch == '-') f = -1;
        ch = getchar();
    } while('0' <= ch && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    } return x * f;
}
inline void pushup(int cur)
{
	p[cur].sum=p[cur<<1].sum+p[cur<<1|1].sum;
	p[cur].msum=max(max(p[cur<<1].msum,p[cur<<1|1].msum),p[cur<<1|1].lsum+p[cur<<1].rsum);
	p[cur].lsum=max(p[cur<<1].lsum,p[cur<<1|1].lsum+p[cur<<1].sum);
	p[cur].rsum=max(p[cur<<1|1].rsum,p[cur<<1].rsum+p[cur<<1|1].sum);
}
inline void build(int l,int r,int cur)
{
	p[cur].l=l;
	p[cur].r=r;
	p[cur].lsum=p[cur].rsum=p[cur].msum=p[cur].sum=0;
	if(l==r)
	{
		a[l]=read();
		p[cur].lsum=p[cur].rsum=p[cur].msum=p[cur].sum=a[l];
		return ;
	}
	int mid=l+r>>1;
	build(l,mid,cur<<1);
	build(mid+1,r,cur<<1|1);
	pushup(cur);
}
inline void update(int pos,int v,int cur)
{
	int L=p[cur].l;
	int R=p[cur].r;
	if(L==R)
	{
		p[cur].sum=p[cur].lsum=p[cur].rsum=p[cur].msum=v;
		return ;
	}
	int mid=L+R>>1;
	if(pos<=mid) update(pos,v,cur<<1);
	else update(pos,v,cur<<1|1);
	pushup(cur);
}
inline node query(int l,int r,int cur)
{
	int LL=p[cur].l;
	int RR=p[cur].r;
	if(l<=LL&&RR<=r) return p[cur];
	int mid=LL+RR>>1;
	node lll,rr,ans;
	if(r<=mid) return query(l,r,cur<<1);
	else if(l>mid) return query(l,r,cur<<1|1);
	else
	{
		lll=query(l,mid,cur<<1);
		rr=query(mid+1,r,cur<<1|1);
		ans.sum=lll.sum+rr.sum;
		ans.msum=max(max(lll.msum,rr.msum),lll.rsum+rr.lsum);
		ans.lsum=max(lll.lsum,lll.sum+rr.lsum);
		ans.rsum=max(rr.rsum,rr.sum+lll.rsum);
		return ans;
	}
}
int main()
{
	int op,l,r;
	while(~scanf("%d",&n))
	{
		build(1,n,1);
		m=read();
		while(m--)
		{
			op=read(),l=read(),r=read();
			if(op==0) update(l,r,1);
			else 
			{
				ans=-inf;
				L=R=0;
				node ans=query(l,r,1);
				printf("%d\n",ans.msum);
			}
		}
	}
	return 0;
}

努力加油a啊,(o)/~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

starlet_kiss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值