POJ_2750_Potted Flower_线段树

还有一周就十一了啊,七天没网的生活即将到来。。。。。


题意:

有一个长为n的环,每个位置有一个整数值,可能为正可能为负,在线单点更新某些点的值,每次更新要求输出最大连续和,且不能是整个环,保证每次的答案都是正数。



Input

There will be a single test data in the input. You are given an integer N (4 <= N <= 100000) in the first input line.

The second line contains N integers, which are the initial attractive value of each potted flower. The i-th number is for the potted flower on the i-th position.

A single integer M (4 <= M <= 100000) in the third input line, and the following M lines each contains an instruction "A B" in the form described above.

Restriction: All the attractive values are within [-1000, 1000]. We guarantee the maximal sum will be always a positive integer.

Output

For each instruction, output a single line with the maximum sum of attractive values for the optimum cane-chair.

虽说线段树的代码写了好多遍了,也写过一些线段树的题,但是这个题一开始还是不会做。。。。。

其实不难,对每个树上的点记录当前的最大连续和、最小连续和(由于环形的原因需要)、和、最小值、从左右端点开始的最大最小连续和(这四个量都是为了更新最大连续和和最小连续和,为了把两个区间从断点连起来)。

ans=max(maxsum[1],sum[1]-minsum[1]);

感觉这个题出题还是有一丢丢问题,保证结果为正数就是这个问题,可能是因为所有元素都为负数的原因吧。为了避免把整个环都取了,需要注意判断是否存在负数,如果存在则肯定会避免那个负数,如果没有负数则要注意不能算上maxsum[1],因为它会记录整个环都算上的情况。


代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
#define mxn 100010
int n;
int a[mxn<<1];
int ll[mxn<<2],rr[mxn<<2];
bool neg[mxn<<2];
int sum[mxn<<2],maxsum[mxn<<2],minsum[mxn<<2],minn[mxn<<2];
int lmaxs[mxn<<2],rmaxs[mxn<<2],lmins[mxn<<2],rmins[mxn<<2];
void eq(int loc,int id){
	if(a[loc]<0)	neg[id]=true;
	else	neg[id]=false;
	minn[id]=a[loc];
	sum[id]=maxsum[id]=minsum[id]=lmaxs[id]=rmaxs[id]=a[loc];
	lmins[id]=rmins[id]=a[loc];
}
void up(int ls,int rs,int id){
	neg[id]=neg[ls]|neg[rs];
	minn[id]=min(minn[ls],minn[rs]);
	sum[id]=sum[ls]+sum[rs];
	maxsum[id]=max(max(maxsum[ls],maxsum[rs]),rmaxs[ls]+lmaxs[rs]);
	minsum[id]=min(min(minsum[ls],minsum[rs]),rmins[ls]+lmins[rs]);
	lmaxs[id]=max(lmaxs[ls],sum[ls]+lmaxs[rs]);
	rmaxs[id]=max(rmaxs[rs],sum[rs]+rmaxs[ls]);
	lmins[id]=min(lmins[ls],sum[ls]+lmins[rs]);
	rmins[id]=min(rmins[rs],sum[rs]+rmins[ls]);
}
void build(int l,int r,int id){
	ll[id]=l,rr[id]=r;
	if(l==r){
		eq(l,id);
		return;
	}
	int m=(l+r)>>1,ls=id<<1,rs=ls|1;
	build(l,m,ls);
	build(m+1,r,rs);
	up(ls,rs,id);
}
void update(int loc,int x,int id){
	if(ll[id]==rr[id]){
		a[loc]=x;
		eq(loc,id);
		return;
	}
	int m=(ll[id]+rr[id])>>1,ls=id<<1,rs=ls|1;
	if(loc<=m)	update(loc,x,ls);
	else	update(loc,x,rs);
	up(ls,rs,id);
}
int main(){
	while(scanf("%d",&n)!=EOF){
		for(int i=0;i<n;++i)	scanf("%d",&a[i]);
		build(0,n-1,1);
		int m;
		scanf("%d",&m);
		int A,B,ans;
		for(int M=0;M<m;++M){
			scanf("%d%d",&A,&B);
			update(A-1,B,1);
			ans=sum[1]-minsum[1];
			if(neg[1])	ans=max(maxsum[1],ans);
			printf("%d\n",ans);
		}
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值