SPOJ - GSS3 Can you answer these queries III

题意:线段树单点修改、区间连续最大值查询。(区间内有负数、正数)
思路:在这里我们需要维护四个值(emmm 这是个模板题,为啥维护四个值,模板就这样我也没办法啊)。lmax、rmax、mmax、sum。含义分别是:左边开始的连续最大值,右边开始的最大值,中间某段的连续最大值和该区间值的总和。
注意核心代码是query代码 updata就是正常的维护即可,要注意的是,当一个点被修改,上述每个值都要被修改。大胆改就完了,反正有pushup呢!注意这里pushup也值得好好琢磨琢磨。
下面是核心代码query函数:
先看这个函数是node类型的,就很不一样!
我的想法:为了保证答案正确(所求区间是完整的且不是重复的)就要用这种结点的形式,而不能采用简单的两边最大和相加!代码如下!

node query(int k,int l,int r){//注意这里求最大子段和就不是原来那样了!!! 
	if(l<=t[k].l&&t[k].r<=r){
		return t[k];
	}else{
		int mid=(t[k].l+t[k].r)>>1;
		if(r<=mid) return query(k<<1,l,r);
		else if(l>mid) return query(k<<1|1,l,r);
		else{
			node a,b,c;
			a=query(k<<1,l,mid);
			b=query(k<<1|1,mid+1,r);
			c.sum=a.sum+b.sum;
			c.lmax=max(a.lmax,a.sum+b.lmax);
			c.rmax=max(b.rmax,b.sum+a.rmax);
			c.mmax=max(max(a.mmax,b.mmax),a.rmax+b.lmax);
			return c;
		}
	}
}

下面是AC代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
#define inf 0x3f3f3f3f
#define cl(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=50000+5;
int n,m;
int a[maxn];
struct node{
	int l,r,lmax,rmax,mmax,sum;
}t[maxn<<2];
void pushup(int k){
	t[k].sum=t[k<<1].sum+t[k<<1|1].sum;
	t[k].lmax=max(t[k<<1].lmax,t[k<<1].sum+t[k<<1|1].lmax);
	t[k].rmax=max(t[k<<1|1].rmax,t[k<<1|1].sum+t[k<<1].rmax);
	t[k].mmax=max(max(t[k<<1].mmax,t[k<<1|1].mmax),t[k<<1].rmax+t[k<<1|1].lmax);
}
void build(int k,int l,int r){
	t[k].l=l,t[k].r=r;
	if(l==r){
		t[k].sum=t[k].mmax=t[k].lmax=t[k].rmax=a[l];
	}else{
		int mid=(l+r)>>1;
		build(k<<1,l,mid);
		build(k<<1|1,mid+1,r);
		pushup(k);
	}
}
void updata(int k,int p,int v){
	if(t[k].l==t[k].r){
		if(t[k].l==p){
			t[k].sum=t[k].mmax=t[k].lmax=t[k].rmax=v;
		}
	}else{
		int mid=(t[k].l+t[k].r)>>1;
		if(p<=mid) updata(k<<1,p,v);
		else if(mid<p) updata(k<<1|1,p,v);
		pushup(k);
	}
}
node query(int k,int l,int r){//注意这里求最大子段和就不是原来那样了!!! 
	if(l<=t[k].l&&t[k].r<=r){
		return t[k];
	}else{
		int mid=(t[k].l+t[k].r)>>1;
		if(r<=mid) return query(k<<1,l,r);
		else if(l>mid) return query(k<<1|1,l,r);
		else{
			node a,b,c;
			a=query(k<<1,l,mid);
			b=query(k<<1|1,mid+1,r);
			c.sum=a.sum+b.sum;
			c.lmax=max(a.lmax,a.sum+b.lmax);
			c.rmax=max(b.rmax,b.sum+a.rmax);
			c.mmax=max(max(a.mmax,b.mmax),a.rmax+b.lmax);
			return c;
		}
	}
}
int main(){
	while(scanf("%d",&n)!=EOF){
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
		}
		build(1,1,n);
		scanf("%d",&m);
		int op,x,y;
		while(m--){
			scanf("%d%d%d",&op,&x,&y);
			if(op==1){
				node temp=query(1,x,y);
				printf("%d\n",temp.mmax);
			}if(op==0){
				updata(1,x,y);
			}
		}
	}
	return 0;
}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值