SPOJ-GSS3- Can you answer these queries III(单点修改+最大字段和)

题目链接:https://vjudge.net/problem/SPOJ-GSS3

Can you answer these queries III

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

给你一个数组,两种操作,0是进行单点修改,1是查询给定区间的最大字段和

单点修改就是个zz,但是最大字段和有点头疼了就,因为无法避免两棵子树的邻接位置的子段求和,这个就让人很头疼,反正我愣是没想出来什么好法去整治他,只能去网上膜拜大神的blog

这个query函数写的就很妙了

void up(node &fa,node &lson,node &rson){//参数要注意 
	fa.sum=lson.sum+rson.sum;//和  
	fa.lmx=max(lson.lmx,lson.sum+rson.lmx);//父亲的左=max(左儿子的左,左儿子+右儿子的左) 
	fa.rmx=max(rson.rmx,rson.sum+lson.rmx);//父亲的右=max(右儿子的右,右儿子+左儿子的右) 
	fa.mx=max(max(lson.mx,rson.mx),lson.rmx+rson.lmx);//父亲的max=max(两个儿子的最大值或者中间的合并最大值) 
}

node query(int k,int l,int r){//区间查询 [pl,pr]的最大子段和  
	if(l<=pp[k].l&&r>=pp[k].r)
		return pp[k];//区间内部 直接返回 
		
	int mid=(pp[k].l+pp[k].r)>>1;
	if(r<=mid)//区间左端 
		return query(k<<1,l,r);
	if(l>mid)//区间右端 
		return query(k<<1|1,l,r);
	//中间地带 
	node ls=query(k<<1,l,r);
	node rs=query(k<<1|1,l,r);
	node res;
	up(res,ls,rs);//
	return res;
}

函数的返回类型直接就是一个结构体,而且最厉害的是想到了中间使用新定义的结构体,这样就不会修改原子树的值,还有就是pushup函数也是想当配合,参数也是结构体,而且是&强制牵引型的,这也太机智了吧

我的脑袋瓜不够用啊 ,对于第一个解出来这道题的大佬 我只能Orz

这里的问题ko之后,完整的代码就是渣渣了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
const int mm=5e4+10;

struct node{
	int l,r;
	int lmx,rmx,mx,sum;
}pp[mm<<2];
int a[mm];

void up(node &fa,node &son,node &rson){//参数要注意 
	fa.sum=lson.sum+rson.sum;//和  
	fa.lmx=max(lson.lmx,lson.sum+rson.lmx);//父亲的左=max(左儿子的左,左儿子+右儿子的左) 
	fa.rmx=max(rson.rmx,rson.sum+lson.rmx);//父亲的右=max(右儿子的右,右儿子+左儿子的右) 
	fa.mx=max(max(lson.mx,rson.mx),lson.rmx+rson.lmx);//父亲的max=max(两个儿子的最大值或者中间的合并最大值) 
}

void build(int k,int l,int r){
	pp[k].l=l;
	pp[k].r=r;
	pp[k].lmx=pp[k].rmx=pp[k].mx=pp[k].sum=0;
	if(l==r){
		pp[k].lmx=pp[k].rmx=pp[k].sum=pp[k].mx=a[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	up(pp[k],pp[k<<1],pp[k<<1|1]);
}

void change(int k,int x,int y){//单点修改 ,将x点的数改成 y 
	if(pp[k].l==pp[k].r){
		pp[k].lmx=pp[k].rmx=pp[k].mx=pp[k].sum=y;
		return ;
	}
	int mid=(pp[k].l+pp[k].r)>>1;
	if(x<=mid)change(k<<1,x,y);
	else change(k<<1|1,x,y);
	up(pp[k],pp[k<<1],pp[k<<1|1]);
}

node query(int k,int l,int r){//区间查询 [pl,pr]的最大子段和  
	if(l<=pp[k].l&&r>=pp[k].r)
		return pp[k];//区间内部 直接返回 
		
	int mid=(pp[k].l+pp[k].r)>>1;
	if(r<=mid)//区间左端 
		return query(k<<1,l,r);
	if(l>mid)//区间右端 
		return query(k<<1|1,l,r);
	//中间地带 
	node ls=query(k<<1,l,r);
	node rs=query(k<<1|1,l,r);
	node res;
	up(res,ls,rs);//
	return res;
}

int n,m,op; 
int x,y;
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	build(1,1,n);
	
	cin>>m;
	while(m--){
		cin>>op>>x>>y;
		if(op==0)
			change(1,x,y);
		else 	
			printf("%d\n",query(1,x,y).mx);
	}
	
	return 0;
}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值