【线段树】jzoj1537 pot 纪中集训提高B组

1537 pot (Standard IO)
Time Limits: 1000 ms Memory Limits: 65536 KB Detailed Limits

Description

这个假期,小h在自家院子里种了许多花,它们围成了一个圈,从1…n编号(n<=100000),小h 对每盆花都有一个喜好值xi,(-1000<=xi<=1000),小h现在觉得这样一成不变很枯燥,于是他做了m(m<=100000)个改动,每次把第ki盘花改成喜好值为di的花,然后小h要你告诉他,在这个花圈中,连续的最大喜好值是多少。

Input

第一行,n,花盆的数量
第二行,n个数,表示对于每盆花的喜好值。
第三行:m, 改动的次数
以下m行,每行两个数ki 和di 。

Output

M行,每一行对应一个更改,表示连续的最大喜好值,且不能整圈都选。(注意:是在圈上找)

Sample Input

5
3 -2 1 2 -5
4
2 -2
5 -5
2 -4
5 -1

Sample Output

4
4
3
5


这种题目描述怎么看怎么像是数据结构题。
怎么看怎么像是线段树。
怎么看怎么像是线段树维护最大子段和问题。
带修最大子段和模板
但是这道题是在环上取,所以可能会出现这种情况,即答案是在两端的红色部分取到:

所以我们再维护一个最小子段和,答案就是整个区间的和减去最小子段和。
还有就是题目要求不能在环上取,所以需要判断一下,如果总和等于最大子段和,就输出整个区间的和减去最小子段和。

#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
#include<queue>
#include<cstdlib>
using namespace std;
#define N 100005
#define ll long long
#define INF 0x3f3f3f3f
struct node{
	int sum,minl,maxl,minr,maxr,minn,maxx;
}tree[N*4];
int n,m,a[N];
inline int rd()
{
	int f=1,x=0;char c=getchar();
	while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();}
	while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return f*x;
}
//-----
void PushUp(int i)
{
	int ls=i<<1,rs=i<<1|1;
	tree[i].sum=tree[ls].sum+tree[rs].sum;
	tree[i].maxl=max(tree[ls].maxl,tree[ls].sum+tree[rs].maxl);
	tree[i].maxr=max(tree[rs].maxr,tree[rs].sum+tree[ls].maxr);
	tree[i].minl=min(tree[ls].minl,tree[ls].sum+tree[rs].minl);
	tree[i].minr=min(tree[rs].minr,tree[rs].sum+tree[ls].minr);
	tree[i].maxx=max(max(tree[ls].maxx,tree[rs].maxx),tree[ls].maxr+tree[rs].maxl);
	tree[i].minn=min(min(tree[ls].minn,tree[rs].minn),tree[ls].minr+tree[rs].minl);
}
void build(int i,int l,int r)
{
	if(l==r)
	{
		tree[i].sum=tree[i].minn=tree[i].maxx=a[l];
		tree[i].minl=tree[i].maxl=a[l];
		tree[i].minr=tree[i].maxr=a[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(i<<1,l,mid);
	build(i<<1|1,mid+1,r);
	PushUp(i);
}
void update(int i,int pos,int val,int l,int r)
{
	if(l==r)
	{
		tree[i].sum=tree[i].minn=tree[i].maxx=val;
		tree[i].minl=tree[i].maxl=val;
		tree[i].minr=tree[i].maxr=val;
		return ;
	}
	int mid=(l+r)>>1;
	if(pos<=mid) update(i<<1,pos,val,l,mid);
	else update(i<<1|1,pos,val,mid+1,r);
	PushUp(i);
}
//-----
int main()
{
	n=rd();
	for(int i=1;i<=n;i++)
		a[i]=rd();
	build(1,1,n);
	m=rd();
	while(m--)
	{
		int x=rd(),y=rd();
		update(1,x,y,1,n);
		if(tree[1].sum==tree[1].maxx)//题目说不能取整圈 
		{
			printf("%d\n",tree[1].sum-tree[1].minn);
			continue;
		}
		printf("%d\n",max(tree[1].maxx,tree[1].sum-tree[1].minn));
	}
	return 0;
}

以下是打丑了的,怎么调都调不出来然后也不想调这种无脑代码的暴力代码:

#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
#include<queue>
#include<cstdlib>
using namespace std;
#define N 100005
#define ll long long
#define INF 0x3f3f3f3f
#define MOD 1000000000
inline int rd()
{
	int f=1,x=0;char c=getchar();
	while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();}
	while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return f*x;
}
int n,m,a[N],s[N];
int main()
{
	n=rd();
	for(int i=1;i<=n;i++)
		a[i]=rd();
	for(int i=n+1;i<=2*n;i++)
		a[i]=a[i-n];
	int ans=0;
	m=rd();
	for(int i=1;i<=m;i++)
	{
		int k=rd(),d=rd();
		if(a[k]==d&&ans)
		{
			printf("%d\n",ans);
			continue;
		}
		ans=0;
		a[k]=a[k+n]=d;
		s[0]=0;
		for(int j=k;j<=2*n;j++)
			s[j]=s[j-1]+a[j];
		for(int j=n+1;j<=2*n;j++)
			for(int len=1;len<n;len++)
				ans=max(ans,s[j]-s[j-len]);
		printf("%d\n",ans);
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值