【线段树】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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值