POJ.2750.Potted Flower(线段树 最大环状子段和)

题目链接

/*
13904K 532ms
最大 环状 子段和有两种情况,比如对于a1,a2,a3,a4,a5 
一是两个端点都取,如a4,a5,a1,a2,那就是所有数的和减去不选的,即可以计算总和减最小连续子段和 
二是两个端点不都取,如a1,a2,a3,那需要记录最大连续子段和 
线段树,令maxs[l,r]为[l,r]上最大连续子段和,mins[l,r]同理 
在向上更新时,可能是由整个左右节点拼成,也可能是只由左或右更新,也可能两段都有,但不包括最左/右端点 
所以还需要记录包括区间左端点的maxsl,minsl,包括区间右端点的maxsr,minsr 
那PushUp的转移就很好写了。见PushUp 

是要求最大真子段和,不能包括所有点,要特判!
*/
#include<cstdio>
#include<cctype>
#include<algorithm>
//#define gc() getchar()
#define gc() (SS==TT &&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
#define lson node[rt].ls
#define rson node[rt].rs
const int N=2e5+5,MAXIN=5e6;

int n;
char IN[MAXIN],*SS=IN,*TT=IN;
inline int read()
{
    int now=0,f=1;register char c=gc();
    for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now*f;
}
struct Seg_Tree
{
    int tot;
    struct Node
    {
        int l,r,ls,rs,sum,maxs,mins,maxsl,maxsr,minsl,minsr;
        void Set(int v)
        {
            sum=maxs=mins=maxsl=maxsr=minsl=minsr=v;
        }
    }node[N<<1];
    inline void PushUp(int rt)
    {
        node[rt].sum=node[lson].sum+node[rson].sum;
        node[rt].maxs=std::max(std::max(node[lson].maxs,node[rson].maxs),node[lson].maxsr+node[rson].maxsl);
        node[rt].mins=std::min(std::min(node[lson].mins,node[rson].mins),node[lson].minsr+node[rson].minsl);
        node[rt].maxsl=std::max(node[lson].maxsl,node[lson].sum+node[rson].maxsl);
        node[rt].minsl=std::min(node[lson].minsl,node[lson].sum+node[rson].minsl);
        node[rt].maxsr=std::max(node[rson].maxsr,node[rson].sum+node[lson].maxsr);
        node[rt].minsr=std::min(node[rson].minsr,node[rson].sum+node[lson].minsr);
    }
    void Build(int l,int r)
    {
        int p=tot++;
        node[p].l=l, node[p].r=r;
        if(l==r)
        {
            node[p].ls=node[p].rs=-1;
            node[p].Set(read());
//          node[p].sum=node[p].maxs=node[p].mins=node[p].maxsl=node[p].minsl=node[p].maxsr=node[p].minsr=read();
            return;
        }
        int m=l+r>>1;
        node[p].ls=tot, Build(l,m);
        node[p].rs=tot, Build(m+1,r);
        PushUp(p);
    }
    void Modify(int rt,int pos,int v)
    {
        if(node[rt].l==node[rt].r){node[rt].Set(v); return;}
        int m=node[rt].l+node[rt].r>>1;
        if(pos<=m) Modify(lson,pos,v);
        else Modify(rson,pos,v);
        PushUp(rt);
    }
//  int Query_Max(int rt,int L,int R)
//  {
//      if(L<=node[rt].l && node[rt].r<=R) return node[rt].maxs;
//      int m=node[rt].l+node[rt].r>>1;
//      if(L<=m)
//          if(m<R) return std::max(Query_Max(lson,L,R),Query_Max(rson,L,R));
//          else Query_Max(lson,L,R);
//      return Query_Max(rson,L,R);
//  }
//  int Query_Min(int rt,int L,int R)
//  {
//      if(L<=node[rt].l && node[rt].r<=R) return node[rt].mins;
//      int m=node[rt].l+node[rt].r>>1;
//      if(L<=m)
//          if(m<R) return std::min(Query_Min(lson,L,R),Query_Min(rson,L,R));
//          else Query_Min(lson,L,R);
//      return Query_Min(rson,L,R);
//  }
}t;

int main()
{
#ifndef ONLINE_JUDGE
    freopen("2750.in","r",stdin);
#endif

    n=read();
    t.Build(1,n);
    int m=read(),p,v;
    while(m--)
        p=read(),v=read(),t.Modify(0,p,v),
        printf("%d\n",t.node[0].sum==t.node[0].maxs? t.node[0].sum-t.node[0].mins : std::max(t.node[0].maxs,t.node[0].sum-t.node[0].mins));//全是正数则要减去一个最小值 
//      printf("%d\n",std::max(t.Query_Max(0,1,n),t.node[0].sum-t.Query_Min(0,1,n)));
//  printf("Max:%d Min:%d sum:%d\n",t.Query_Max(0,1,n),t.Query_Min(0,1,n),t.node[0].sum);

    return 0;
}

转载于:https://www.cnblogs.com/SovietPower/p/8444259.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值