poj 2750 Potted Flower

题目链接如下所示:

2750 -- Potted Flower

线段树和DP的结合。

首先,关于DP,对于一个区间[a,b],我们维护最大序列和max_sum,相应最小序列和min_sum,维护以a开头的最大最小序列和lmax,lmin,相应以b结尾的最大最小序列和为rmax,rmin,同样记录一个sum来表示区间总和。在push_up的时候我们自底向上更新序列和:

1.对于max_sum,我们对当前节点左右孩子最大的区间和,以及左孩子的rmax和右孩子的lmax之和三者取其最大。min_sum类似。

2.对于lmax,我们对当前节点的左孩子的lmax,左孩子的sum和有孩子的lmax之和作比较,取两者最大的一个。其余类似。

3.sum当然要一直累加。

接下来就是在建树和update的时候更新push_up即可。

代码如下所示:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<vector>
#include<algorithm>
#include<cstring>
#include<set>
#include<map>
#include<queue>
#include<string>
#include<cmath>
#include<climits>

using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int MAXN=100005;
int sum[MAXN<<2],max_sum[MAXN<<2],min_sum[MAXN<<2];
int lmax[MAXN<<2],rmax[MAXN<<2];
int lmin[MAXN<<2],rmin[MAXN<<2];
int a[MAXN];

void push_up(int rt){
    int l=rt<<1;
    int r=rt<<1|1;
    sum[rt]=sum[l]+sum[r];
    max_sum[rt]= max(max(max_sum[l],max_sum[r]),rmax[l]+lmax[r]);
    min_sum[rt]= min(min(min_sum[l],min_sum[r]),rmin[l]+lmin[r]);
    lmax[rt]= max(lmax[l],sum[l]+lmax[r]);
    rmax[rt]= max(rmax[r],sum[r]+rmax[l]);
    lmin[rt]= min(lmin[l],sum[l]+lmin[r]);
    rmin[rt]= min(rmin[r],sum[r]+rmin[l]);
}

void build(int l,int r,int rt){
    if (l==r){
        max_sum[rt]=min_sum[rt]=a[l];
        lmax[rt]=rmax[rt]=lmin[rt]=rmin[rt]=a[l];
        sum[rt]=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
    push_up(rt);
}

void update(int pos,int val,int l,int r,int rt){
    if (l==r){
        max_sum[rt]=min_sum[rt]=val;
        lmax[rt]=rmax[rt]=lmin[rt]=rmin[rt]=val;
        sum[rt]=val;
        return;
    }
    int mid=(l+r)>>1;
    if (pos<=mid){
        update(pos,val,lson);
    } else{
        update(pos,val,rson);
    }
    push_up(rt);
}

int main(){
    int n,m;
    int pos,val,ans;
    scanf("%d",&n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d",&a[i]);
    }
    build(1,n,1);
    scanf("%d",&m);
    while (m--){
        scanf("%d %d",&pos,&val);
        update(pos,val,1,n,1);
        if (sum[1]==max_sum[1]){
            ans=sum[1]-min_sum[1];
        }else{
            ans=max(sum[1]-min_sum[1],max_sum[1]);
        }
        printf("%d\n",ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值