Poj 2750 Potted Flower

普通的线段树
题面:一个环上每一个点都有一个权值,要求支持单点更新,查询最大连续子序列和
ps:查询的时候子序列的大小不能超过n,也就是不能把所有的数都选起来

如果不是环上,是区间上的话,这题就解决了(如果不知道怎么做的话,看这里

这个题和之前的那个题差别在于这题是一个环上的(废话!
如果要特判的话,那人生也太可悲了
如果换一个角度呢,也就是说我们考虑如果所求的区间是从1和n这两个地方穿过的
这个时候的答案是不是就等于 i=1na[i](1n)

这种情况就处理完了,然后还有要注意的是不能全取也不能全不取
思考一下什么情况下会全取:(所有数都是正数的时候
这个时候区间和就等于区间最大连续子序列,需要返回的是所有数的和-最小的那个数
同时值得注意的是,有时候不全是正数但是也会有区间和等于区间最大连续子序列的情况,考虑如下数据
3 4 5 -3 -4 -5 3 4 5
这个时候应该返回的是区间和-区间最小连续子序列(想一想,为什么
全不取也同样思考一下,会发现这个时候所有的节点都是负数
那么这个时候我们应该返回最小的那个点
剩下的情况就是max(最大连续子序列,区间和-最小连续子序列)

顺便再安利一波这种重载加号来表示区间合并的方法,感觉十分及其的好用

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int maxn = 112345;
#define LL int

struct Info{
    LL lmax,rmax;
    LL lmin,rmin;
    LL nmin,nmax;
    LL smax,smin;
    LL sum;
    void init(LL v){
        sum = v;
        smax = lmax = rmax = nmax = v;
        smin = lmin = rmin = nmin = v;
    }
    LL value(){
        if(smax == sum){
            return sum - smin;
        }
        if(smin == sum){
            return nmax;
        }
        return  max(smax,sum - smin);
    }
};

Info operator + (const Info &L,const Info &R){
    Info ret;
    ret.nmin=min(L.nmin,R.nmin);
    ret.nmax=max(L.nmax,R.nmax);
    ret.lmax=max(L.lmax,L.sum+R.lmax);
    ret.rmax=max(R.rmax,R.sum+L.rmax);
    ret.lmin=min(L.lmin,L.sum+R.lmin);
    ret.rmin=min(R.rmin,R.sum+L.rmin);
    ret.sum = L.sum+R.sum;
    ret.smax = max(max(L.smax,R.smax),L.rmax+R.lmax);
    ret.smin = min(min(L.smin,R.smin),L.rmin+R.lmin);
    return ret;
}

#define root 1,1,n
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define Mid int m = l + (r-l)/2
#define Now int o,int l,int r

Info arr[maxn*4];

void update(Now,int pos,int v){
    if(l==r){
        arr[o].init(v);
        return;
    }
    Mid;
    if(pos <= m){
        update(lson,pos,v);
    }
    else{
        update(rson,pos,v);
    }
    arr[o] = arr[o<<1] + arr[o<<1|1];
}

LL query(){
    return arr[1].value();
}
int main(){
    int n;
    while(~scanf("%d",&n)){
        LL x;
        for(int i=1;i<=n;i++){
            scanf("%d",&x);
            update(root,i,x);
        }
        int m;
        scanf("%d",&m);
        int pos;
        while(m--){
            scanf("%d %d",&pos,&x);
            update(root,pos,x);
            printf("%d\n",query());
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值