http://poj.org/problem?id=2750
/*
问题描述:给定一个环形序列,进行在线操作,每次修改一个元素,输出环上的最大连续子列的和,但不能是完全序列。
算法:把环从一个地方,切断拉成一条直线,用线段树记录当前区间的非空最大子列和当前区间的非空最小子列。
动态规划解决过静态的序列最大连续子序列和问题,时间复杂度可以达到 n(环形序列可能复杂度更高)。但是这里涉及到动态更新,更新频度很大,如果计算子序列和复杂度仍然是n,就会非常耗时。
如果环上的数都是正整数,答案是:环上数的总和-根结点的非空最小子列;否则,答案是:max{根结点的非空最大子列, 环上数的总和-根结点的非空最小子列}
一开始想到,如果将环从一点断开,那么最大和如果包括断点的最后一个点和第一个点,那该如何求
,仔细看了一下 ,终于向明白了,如果 段的最大自序列包括 断点 那么断点一定是正数;
那么 环上数的总和-根结点的非空最小子列,就将断点包括了。
*/
#include<stdio.h>
#include<iostream>
#define N 100050
using namespace std;
int n,m;
int a[N];
struct node
{
int l,r,sum;
int xmax,xmin;
int lmax,lmin;
int rmax,rmin;
}p[N*3];
void update(int x)
{
p[x].sum=p[x*2].sum+p[x*2+1].sum;
p[x].lmax=max(p[x*2].lmax,p[x*2].sum+p[x*2+1].lmax);
p[x].rmax=max(p[x*2+1].rmax,p[x*2].rmax+p[x*2+1].sum);//跨区间求最值
p[x].xmax=max(max(p[x*2].xmax,p[x*2+1].xmax),p[x*2].rmax+p[x*2+1].lmax);
p[x].lmin=min(p[x*2].lmin,p[x*2].sum+p[x*2+1].lmin);
p[x].rmin=min(p[x*2+1].rmin,p[x*2].rmin+p[x*2+1].sum);
p[x].xmin=min(min(p[x*2].xmin,p[x*2+1].xmin),p[x*2].rmin+p[x*2+1].lmin);
}
void build(int x,int l,int r)
{
p[x].l=l;
p[x].r=r;
if(l==r)
{
p[x].sum=p[x].xmax=p[x].xmin=a[l];
p[x].lmax=p[x].lmin=a[l];
p[x].rmax=p[x].rmin=a[l];
return ;
}
int mid=(l+r)/2;
build(x*2,l,mid);
build(x*2+1,mid+1,r);
update(x);
}
void change(int x,int pos,int y)
{
if(p[x].l==p[x].r&&p[x].l==pos)
{
p[x].sum=p[x].xmax=p[x].xmin=y;
p[x].lmax=p[x].lmin=y;
p[x].rmax=p[x].rmin=y;
return ;
}
int mid=(p[x].l+p[x].r)/2;
if(pos<=mid)change(x*2,pos,y);
else change(x*2+1,pos,y);
update(x);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
build(1,1,n);
scanf("%d",&m);
int pos,y;
while(m--)
{
scanf("%d%d",&pos,&y);
change(1,pos,y);
//printf("%d %d %d\n",p[1].sum,p[1].xmax,p[1].xmin);
if(p[1].sum==p[1].xmax)
{
printf("%d\n",p[1].sum-p[1].xmin);
}
else
{
printf("%d\n",max(p[1].xmax,p[1].sum-p[1].xmin));
}
}
}