比较经典的segment tree的应用,线段树中信息的巧妙设计能够使得整个区间的解可以由合并子区间的解得到,本题很好的体现了这一点。

#include <stdio.h>
#include <string.h>

const int MAXN = 50005;

typedef struct {
    int sum;        //[l..r]的所有元素和
    int prefix;     //[l..r]的最大前缀和
    int suffix;     //[l..r]的最大后缀和
    int max;        //[l..r]的最大子段和
    int l;
    int r;
}Node;

Node seg[MAXN * 3];
int a[MAXN];
int N,M;

int fmax(int a,int b)
{
    return a > b ? a : b;
}

void up(int num)
{
    //bottom-up的递推过程
    seg[num].sum = seg[num << 1].sum + seg[num << 1 | 1].sum;
    seg[num].prefix = fmax(seg[num << 1].prefix, seg[num << 1].sum + seg[num << 1 | 1].prefix);
    seg[num].suffix = fmax(seg[num << 1 | 1].suffix, seg[num << 1 | 1].sum + seg[num << 1].suffix);
    seg[num].max = fmax(fmax(seg[num << 1].max, seg[num << 1 | 1].max), seg[num << 1].suffix + seg[num << 1 | 1].prefix);
}

void build(int num,int l,int r)
{
    seg[num].l = l;
    seg[num].r = r;

    if ( l == r )
    {
        seg[num].sum = seg[num].prefix = seg[num].suffix = seg[num].max = a[l];
        return;
    }

    int m = ( l + r ) >> 1;
    build(num << 1, l, m);
    build(num << 1 | 1, m + 1, r);
    up(num);
}

void update(int num,int id,int value)
{
    if ( seg[num].l == id && seg[num].r == id )
    {
        seg[num].sum = seg[num].prefix = seg[num].suffix = seg[num].max = value;
        return;
    }

    int m = ( seg[num].l + seg[num].r ) >> 1;
    if ( id <= m )
        update(num << 1, id, value);
    else
        update(num << 1 | 1, id, value);

    up(num);
}

int query_sum(int num,int l,int r)
{
    if ( seg[num].l == l && seg[num].r == r )
        return seg[num].sum;

    int m = ( seg[num].l + seg[num].r ) >> 1;
    if ( r <= m )
        return query_sum(num << 1, l, r);
    if ( m + 1 <= l )
        return query_sum(num << 1 | 1, l, r);
    else
        return query_sum(num << 1, l, m) + query_sum(num << 1 | 1, m + 1, r);
}

int query_prefix(int num,int l,int r)
{
    //查询[l..r]的最大前缀和
    if ( seg[num].l == l && seg[num].r == r )
        return seg[num].prefix;

    int m = ( seg[num].l + seg[num].r ) >> 1;
    if ( r <= m )
        return query_prefix(num << 1, l, r);
    else if ( m + 1 <= l )
        return query_prefix(num << 1 | 1, l, r);
    else
        return fmax(query_prefix(num << 1, l, m),query_sum(num << 1, l, m) + query_prefix(num << 1 | 1, m + 1, r));
}

int query_suffix(int num,int l,int r)
{
    //查询[l..r]的最大后缀和
    if ( seg[num].l == l && seg[num].r == r )
        return seg[num].suffix;

    int m = ( seg[num].l + seg[num].r ) >> 1;
    if ( r <= m )
        return query_suffix(num << 1, l, r);
    else if ( m + 1 <= l )
        return query_suffix(num << 1 | 1, l, r);
    else
        return fmax(query_suffix(num << 1 | 1, m + 1, r), query_sum(num << 1 | 1, m + 1, r) + query_suffix(num << 1, l, m));
}

int query(int num,int l,int r)
{
    if ( seg[num].l == l && seg[num].r == r)
        return seg[num].max;

    int m = ( seg[num].l + seg[num].r ) >> 1;
    if ( r <= m )
        return query(num << 1, l, r);
    else if ( m + 1 <= l )
        return query(num << 1 | 1, l, r);
    else
    {
        int ans = fmax(query(num << 1, l, m), query(num << 1 | 1, m + 1, r));
        ans = fmax(ans, query_suffix(1, l, m) + query_prefix(1, m + 1, r));
        return ans;
    }
}

int main()
{
//    freopen("1.txt","r",stdin);

    scanf("%d",&N);
    for (int i = 1; i <= N; i++)
        scanf("%d",&a[i]);

    build(1,1,N);

    scanf("%d",&M);

    int u,v,w;
    while ( M-- )
    {
        scanf("%d%d%d",&u,&v,&w);
        if ( u == 0 )
        {
            a[v] = w;
            update(1,v,w);
        }
        else
            printf("%d\n",query(1,v,w));
    }

    return 0;
}

 

 

 

posted on 2013-06-24 23:29  Sinker  阅读(491)  评论(0编辑  收藏  举报