POJ 2750 Potted Flower(线段树 + DP)

题目链接:http://poj.org/problem?id=2750

 

题意:给出N个数成环,再给M个操作,每次操作会改变某个数的数值,问每次更新完成后区间的最大和是多少,该区间不能是整个区间

 

思路:将环从某点切开看成一段序列,对于一个区间而言,如过所选序列不包括断点,那么直接求区间最大连续和smax即可,如果包括断点,那么答案则为max(smax, sum - smin),sum为区间总和,smin为区间最小连续和。

对于更新可以用线段树维护以下信息,sum为区间和,lmax为区间从左至右最大连续和,rmax为区间从右至左最大连续和,smax为区间最大连续和(最小连续和也同样处理)

故而有转移:

tr[rt].lmax = max(tr[ls].lmax, tr[ls].sum + tr[rs].lmax);       

tr[rt].rmax = max(tr[rs].rmax, tr[rs].sum + tr[ls].rmax);

tr[rt].smax = max(max(tr[ls].smax, tr[rs].smax), tr[ls].rmax + tr[rs].lmax);        

 

 

 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#include <climits>
#include <functional>
#include <deque>
#include <ctime>

#define ls rt << 1
#define rs rt << 1 | 1
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#pragma comment(linker, "/STACK:102400000,102400000")

using namespace std;

const int maxn = 100010;

struct segtree
{
    int sum;
    int lmax, rmax, smax;
    int lmin, rmin, smin;
} tr[maxn << 2];

void pushup(int rt)
{
    tr[rt].sum = tr[ls].sum + tr[rs].sum;

    tr[rt].lmax = max(tr[ls].lmax, tr[ls].sum + tr[rs].lmax);       
    tr[rt].rmax = max(tr[rs].rmax, tr[rs].sum + tr[ls].rmax);
    tr[rt].smax = max(max(tr[ls].smax, tr[rs].smax), tr[ls].rmax + tr[rs].lmax);

    tr[rt].lmin = min(tr[ls].lmin, tr[ls].sum + tr[rs].lmin);
    tr[rt].rmin = min(tr[rs].rmin, tr[rs].sum + tr[ls].rmin);
    tr[rt].smin = min(min(tr[ls].smin, tr[rs].smin), tr[ls].rmin + tr[rs].lmin);
}

void build(int l, int r, int rt)
{
    if (l == r)
    {
        scanf("%d", &tr[rt].sum);
        tr[rt].lmax = tr[rt].rmax = tr[rt].smax = tr[rt].sum;
        tr[rt].lmin = tr[rt].rmin = tr[rt].smin = tr[rt].sum;
        return ;
    }

    int mid = (l + r) >> 1;
    build(lson);
    build(rson);
    pushup(rt);
}

void update(int p, int c, int l, int r, int rt)
{
    if (l == r)
    {
        tr[rt].sum = c;
        tr[rt].lmax = tr[rt].rmax = tr[rt].smax = c;
        tr[rt].lmin = tr[rt].rmin = tr[rt].smin = c;
        return ;
    }

    int mid = (l + r) >> 1;
    if (p <= mid)
        update(p, c, lson);
    else
        update(p, c, rson);
    pushup(rt);
}

int main()
{
    int n;
    while (~scanf("%d", &n))
    {
        build(1, n, 1);

        int m;
        scanf("%d", &m);
        while (m--)
        {
            int p, c;
            scanf("%d%d", &p, &c);
            update(p, c, 1, n, 1);

            if (tr[1].sum == tr[1].smax)
                printf("%d\n", tr[1].sum - tr[1].smin);
            else
                printf("%d\n", max(tr[1].smax, tr[1].sum - tr[1].smin));
        }
    }
    return 0;
}

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值