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;
}