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