题目描述
给出一个含有N个结点的环,编号分别为1..N,环上的点带有权值(可正可负),现要动态的修改某个点的权值,求每次修改后环上的最大连续和,但不能是整个序列的和。
题目大意
单点修改,求环上的最大和。
数据范围
(4<=N,M<=100000)(不会爆int)
样例输入
5
3 -2 1 2 -5
4
2 -2
5 -5
2 -4
5 -1
样例输出
4
4
3
5
解题思路
线段树,维护:↓(最大值与最小值是指这一段的和的最大值与最小值)
Max(区间最大值),MaxL(从左端开始的区间最大值),Maxr(从右端开始的区间最大值)
Min(区间最小值),MinL(从左端开始的区间最小值),Minr(从右端开始的区间最小值)
Sum(区间和),MinMin(这个东西我也不确定是否为必须的,以前做没有修改的环上的最大和时用过的,就加上吧233)
所以对环上最大和的询问的Ans就是(1-n这个区间的最大值)和(Sum-区间最小值)中的最大值A.A
代码
#include <bits/stdc++.h>
using namespace std;
inline int Getint(){int x=0,f=1;char ch=getchar();while('0'>ch||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
int vl[100005],Sum=0,All=0;
struct node{
int L,r,Max,MaxL,Maxr,Min,MinL,Minr,Sum,MinMin;
}Tree[400005];
void PushUp(int v){
Tree[v].Max=max(Tree[2*v].Max,Tree[2*v+1].Max);
Tree[v].Max=max(Tree[2*v].Maxr+Tree[2*v+1].MaxL,Tree[v].Max);
Tree[v].MaxL=max(Tree[2*v].MaxL,Tree[2*v].Sum+Tree[2*v+1].MaxL);
Tree[v].Maxr=max(Tree[2*v+1].Maxr,Tree[2*v+1].Sum+Tree[2*v].Maxr);
Tree[v].Max=max(Tree[v].MaxL,Tree[v].Max);
Tree[v].Max=max(Tree[v].Maxr,Tree[v].Max);
Tree[v].Min=min(Tree[2*v].Min,Tree[2*v+1].Min);
Tree[v].Min=min(Tree[2*v].Minr+Tree[2*v+1].MinL,Tree[v].Min);
Tree[v].MinL=min(Tree[2*v].MinL,Tree[2*v].Sum+Tree[2*v+1].MinL);
Tree[v].Minr=min(Tree[2*v+1].Minr,Tree[2*v+1].Sum+Tree[2*v].Minr);
Tree[v].Min=min(Tree[v].MinL,Tree[v].Min);
Tree[v].Min=min(Tree[v].Minr,Tree[v].Min);
Tree[v].Sum=Tree[2*v].Sum+Tree[2*v+1].Sum;
Tree[v].MinMin=min(Tree[2*v].MinMin,Tree[2*v+1].MinMin);
}
void Build(int v,int L,int r){
Tree[v]=(node){L,r,-1<<30,-1<<30,-1<<30,1<<30,1<<30,1<<30,0};
if(L==r)return;
Build(2*v,L,(L+r)/2);
Build(2*v+1,(L+r)/2+1,r);
}
void Insert(int v,int pos,int val){
if(pos<Tree[v].L||Tree[v].r<pos)return;
if(Tree[v].L==Tree[v].r){
Tree[v]=(node){Tree[v].L,Tree[v].r,val,val,val,val,val,val,val,val};
return;
}
Insert(2*v,pos,val);
Insert(2*v+1,pos,val);
PushUp(v);
}
int n;
void Solve(int pos,int val){
Sum=Sum-vl[pos]+val;
All-=vl[pos]<0;
vl[pos]=val;
All+=vl[pos]<0;
Insert(1,pos,val);
int Max=Tree[1].Max,Min=Tree[1].Min;
if(All==n)cout<<Max<<"\n";
else{
int Ans=max(Max,Sum-Min);
if(Ans==Tree[1].Sum)Ans-=Tree[1].MinMin;
cout<<Ans<<"\n";
}
}
int main(){
n=Getint();
Build(1,1,n);
for(int i=1;i<=n;i++)Sum+=vl[i]=Getint(),All+=vl[i]<0;
for(int i=1;i<=n;i++)Insert(1,i,vl[i]);
int q=Getint();
while(q--){
int pos=Getint(),val=Getint();
Solve(pos,val);
}
return 0;
}