poj 2750 线段树(带更新的环形最大子序列)

题意:给定一个环形序列,可以进行在线操作,每次修改一个其中元素。每次修改之后立即输出环上的最大连续子序列的和,要求子序列的长度不得为n,也即不能是整个环。

思路:比较复杂的线段树(http://blog.csdn.net/non_cease/article/details/7437690)把环从一个地方切断拉成一条直线(最直观当然是从n~1之间切断),用线段树记录当前区间的非空最大子列和当前区间的非空最小子列。如果环上的数都是正整数,答案是:环上数的总和-根结点的非空最小子列;否则,答案是:max{根结点的非空最大子列,环上数的总和-根结点的非空最小子列},每次问答的复杂度是O(logN)。

结点内记录的内容比较多,需要记录序列的从左向右最大连续序列值lmax,从右往左的最大连续序列值rmax,和从左向右最小连续序列值lmin,从右往左的最小连续序列值rmin,和每个序列的最大连续序列值semax和最小连续序列值semin,以及在当前区域的和sum。更新起来也就比较显然。

#include <stdio.h>
#include <string.h>
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define N 100005
struct node{
    int sum;
    int semax,semin;
    int lmax,rmax;
    int lmin,rmin;
}t[N<<2];
int n,m;
int mid(int a,int b){
    return (a+b)>>1;
}
void update(int r){
    int lson,rson;
    lson = r<<1;
    rson = lson+1;
    t[r].sum = t[lson].sum + t[rson].sum;
    t[r].semax = max(max(t[lson].semax , t[rson].semax), t[lson].rmax+t[rson].lmax);
    t[r].semin = min(min(t[lson].semin , t[rson].semin), t[lson].rmin+t[rson].lmin);
    t[r].lmax = max(t[lson].lmax, t[lson].sum+t[rson].lmax);
    t[r].lmin = min(t[lson].lmin, t[lson].sum+t[rson].lmin);
    t[r].rmax = max(t[rson].rmax, t[rson].sum+t[lson].rmax);
    t[r].rmin = min(t[rson].rmin, t[rson].sum+t[lson].rmin);
    
}
void build(int r,int a,int b){
    int k = mid(a,b);
    if(a == b){
        scanf("%d",&t[r].sum);
        t[r].semax = t[r].semin = t[r].lmax = t[r].lmin = t[r].rmax = t[r].rmin = t[r].sum;
        return;
    }
    build(r*2, a, k);
    build(r*2+1, k+1, b);
    update(r);
}
void alter(int x,int y,int r,int a,int b){
    int k=mid(a,b);
    if(a==x && b==x){
        t[r].sum = y;
        t[r].semax = t[r].semin = t[r].lmax = t[r].lmin = t[r].rmax = t[r].rmin = t[r].sum;
        return;
    }
    if(x<=k)
        alter(x, y, r*2, a, k);
    else
        alter(x, y, r*2+1, k+1, b);
    update(r);
}
int main(){
    int i,x,y;
    scanf("%d",&n);
    build(1,1,n);
    scanf("%d",&m);
    for(i = 0;i<m;i++){
        scanf("%d %d",&x,&y);
        alter(x,y,1,1,n);
        if(t[1].sum == t[1].semax)
            printf("%d\n",t[1].sum-t[1].semin);
        else
            printf("%d\n",max(t[1].sum-t[1].semin, t[1].semax));
    }
    return 0;
}


你可能感兴趣的:(poj 2750 线段树(带更新的环形最大子序列))