SP1716 GSS3 - Can you answer these queries III

题目链接

问题分析

解法一

简单的一道线段树维护\(lmax,rmax,max,sum\)即可。

解法二

考虑动态DP。
\[ \begin{aligned} \left [ \begin{matrix} a_i&-\infty&a_i\\ a_i&0&a_i\\-\infty & -\infty &0 \end{matrix}\right ] \left [\begin{matrix} f_{i-1}\\ g_{i-1}\\ 0 \end{matrix}\right] = \left [\begin{aligned} f_i\\ g_i\\ 0 \end{aligned}\right] \end{aligned} \]
然后线段树维护即可。

参考程序

解法一
#include <bits/stdc++.h>
using namespace std;

const int Maxn = 50010;
struct node {
    int LeftMax, RightMax, Max, Sum;
    node() {}
    node( int _LeftMax, int _RightMax, int _Max, int _Sum) : 
        LeftMax( _LeftMax ), RightMax( _RightMax ), Max( _Max ), Sum( _Sum ) {}
    inline node operator + ( const node Other ) const {
        return node( max( LeftMax, Sum + Other.LeftMax ), 
                max( Other.RightMax, Other.Sum + RightMax ),
                max( max( Max, Other.Max ), RightMax + Other.LeftMax ),
                Sum + Other.Sum );
    }
    inline void Give( int x ) {
        LeftMax = RightMax = Max = Sum = x;
        return;
    }
};
node Tree[ Maxn << 2 ];
int n, m, A[ Maxn ];

void Build( int Index, int Left, int Right ) {
    if( Left == Right ) {
        Tree[ Index ].Give( A[ Left ] );
        return;
    }
    int Mid = ( Left + Right ) >> 1;
    Build( Index << 1, Left, Mid );
    Build( Index << 1 | 1, Mid + 1, Right );
    Tree[ Index ] = Tree[ Index << 1 ] + Tree[ Index << 1 | 1 ];
    return;
}

void Change( int Index, int Left, int Right, int Pos, int Key ) {
    if( Left == Right ) {
        Tree[ Index ].Give( Key );
        return;
    }
    int Mid = ( Left + Right ) >> 1;
    if( Pos <= Mid ) Change( Index << 1, Left, Mid, Pos, Key );
    if( Pos > Mid ) Change( Index << 1 | 1, Mid + 1, Right, Pos, Key );
    Tree[ Index ] = Tree[ Index << 1 ] + Tree[ Index << 1 | 1 ];
    return;
}

node Query( int Index, int Left, int Right, int L, int R ) {
    if( L <= Left && Right <= R ) return Tree[ Index ];
    int Mid = ( Left + Right ) >> 1;
    if( R <= Mid ) return Query( Index << 1, Left, Mid, L, R );
    if( L > Mid ) return Query( Index << 1 | 1, Mid + 1, Right, L, R );
    return Query( Index << 1, Left, Mid, L, R ) + Query( Index << 1 | 1, Mid + 1, Right, L, R );
}

int main() {
    scanf( "%d", &n );
    for( int i = 1; i <= n; ++i ) scanf( "%d", A + i );
    Build( 1, 1, n );
    scanf( "%d", &m );
    for( int i = 1; i <= m; ++i ) {
        int Opt, l, r;
        scanf( "%d%d%d", &Opt, &l, &r );
        if( Opt == 0 ) Change( 1, 1, n, l, r );
        if( Opt == 1 ) printf( "%d\n", Query( 1, 1, n, l, r ).Max );
    }
    return 0;
}
解法二
#include <bits/stdc++.h>
using namespace std;

const int Maxn = 50010;
const int INF = 1000000000;
struct matrix {
    int A[ 3 ][ 3 ];
    matrix() {
        for( int i = 0; i < 3; ++i )
            for( int j = 0; j < 3; ++j )
                A[ i ][ j ] = -INF;
        return;
    }
    matrix( int x ) {
        A[ 0 ][ 0 ] = A[ 0 ][ 2 ] = A[ 1 ][ 0 ] = A[ 1 ][ 2 ] = x;
        A[ 0 ][ 1 ] = A[ 2 ][ 0 ] = A[ 2 ][ 1 ] = -INF;
        A[ 1 ][ 1 ] = A[ 2 ][ 2 ] = 0;
        return;
    }
    inline matrix operator * ( const matrix Other ) const {
        matrix Ans = matrix();
        for( int i = 0; i < 3; ++i )
            for( int j = 0; j < 3; ++j )
                for( int k = 0; k < 3; ++k )
                    Ans.A[ i ][ j ] = max( Ans.A[ i ][ j ], A[ i ][ k ] + Other.A[ k ][ j ] );
        return Ans;
    }
};
int n, m, A[ Maxn ];
matrix Tree[ Maxn << 2 ];

void Build( int Index, int Left, int Right ) {
    if( Left == Right ) {
        Tree[ Index ] = matrix( A[ Left ] );
        return;
    }
    int Mid = ( Left + Right ) >> 1;
    Build( Index << 1, Left, Mid );
    Build( Index << 1 | 1, Mid + 1, Right );
    Tree[ Index ] = Tree[ Index << 1 ] * Tree[ Index << 1 | 1 ];
    return;
}

void Change( int Index, int Left, int Right, int Pos, int Key ) {
    if( Left == Right ) {
        Tree[ Index ] = matrix( Key );
        return;
    }
    int Mid = ( Left + Right ) >> 1;
    if( Pos <= Mid ) Change( Index << 1, Left, Mid, Pos, Key );
    if( Pos > Mid ) Change( Index << 1 | 1, Mid + 1, Right, Pos, Key );
    Tree[ Index ] = Tree[ Index << 1 ] * Tree[ Index << 1 | 1 ];
    return;
}

matrix Query( int Index, int Left, int Right, int L, int R ) {
    if( L <= Left && Right <= R ) return Tree[ Index ];
    int Mid = ( Left + Right ) >> 1;
    if( R <= Mid ) return Query( Index << 1, Left, Mid, L, R );
    if( L > Mid ) return Query( Index << 1 | 1, Mid + 1, Right, L, R );
    return Query( Index << 1, Left, Mid, L, R ) * Query( Index << 1 | 1, Mid + 1, Right, L, R );
}

int main() {
    scanf( "%d", &n );
    for( int i = 1; i <= n; ++i ) scanf( "%d", &A[ i ] );
    Build( 1, 1, n );
    scanf( "%d", &m );
    for( int i = 1; i <= m; ++i ) {
        int Opt, x, y;
        scanf( "%d%d%d", &Opt, &x, &y );
        if( Opt == 0 ) Change( 1, 1, n, x, y );
        if( Opt == 1 ) printf( "%d\n", Query( 1, 1, n, x, y ).A[ 1 ][ 2 ] );
    }
    return 0;
}

转载于:https://www.cnblogs.com/chy-2003/p/11502651.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值