SP1716 GSS3 - Can you answer these queries III(区间最大子段和+单点修改)

题意

给出n个数,q次操作,两种操作:把ax改成y,求[l,r]的最大子段和。

n,m<=50000,-10000<=ai<=10000

题解

区间问题想到用线段树维护,考虑如何合并区间。

当我们求出两段小区间的最大子段和,那么大区间的最大子段和可能是这两个的其中一个,也可能是中间两个区间拼接的部分,这部分就是左区间右边最大的部分和右区间左边最大的部分组成。

所以我们还需要记录区间紧靠左边和紧靠右边的最大子段和,现在考虑维护左边的最大子段和lmax,在区间合并时,大区间的lmax可能是左区间的lmax,也可能是左边整个区间加上右边区间的lmax。rmax同理。

区间查询的时候传结构体才能合并信息。

 

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

#define ls rt<<1
#define rs rt<<1|1
#define ll long long
const int maxn=50005;
int n,m;
int a[maxn];
struct cx{
  ll sum,dat,lmax,rmax;// 区间和,区间最大子段和,左端最大子段和,右端最大子段和
}t[maxn<<2];

ll max(ll x,ll y){return x>y ? x : y ;}

void get(cx &ret,cx lx,cx ry){
  ret.sum=lx.sum+ry.sum;
  ret.lmax=max(lx.lmax,lx.sum+ry.lmax);
  ret.rmax=max(ry.rmax,ry.sum+lx.rmax);
  ret.dat=max(max(lx.dat,ry.dat),lx.rmax+ry.lmax);
}

void build(int rt,int l,int r){
  if(l==r){
    t[rt]=(cx){a[l],a[l],a[l],a[l]};
    return ;
  }
  int mid=(l+r)>>1;
  build(ls,l,mid);
  build(rs,mid+1,r);
  get(t[rt],t[ls],t[rs]);
}

cx query(int rt,int l,int r,int a_l,int a_r){
  //printf("%d %d %d %d \n",l,r,a_l,a_r);
  if(a_l<=l&&r<=a_r) return t[rt];
  int mid=(l+r)>>1;
  if(a_r<=mid) return query(ls,l,mid,a_l,a_r);
  if(mid<a_l) return query(rs,mid+1,r,a_l,a_r);
  cx ret,x,y;
  x=query(ls,l,mid,a_l,a_r);
  y=query(rs,mid+1,r,a_l,a_r);
  get(ret,x,y);
  return ret;
}

void modify(int rt,int l,int r,int pos,int val){
  if(l==r){
    t[rt]=(cx){val,val,val,val};
    return ;
  }
  int mid=(l+r)>>1;
  if(pos<=mid) modify(ls,l,mid,pos,val);
  else modify(rs,mid+1,r,pos,val);
  get(t[rt],t[ls],t[rs]);
}

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;
    scanf("%d",&opt);
    if(opt){
      int l,r;
      scanf("%d%d",&l,&r);
      printf("%lld\n",query(1,1,n,l,r).dat);
    }
    else {
      int pos,val;
      scanf("%d%d",&pos,&val);
      modify(1,1,n,pos,val);
    }
  }
}
View Code

 

转载于:https://www.cnblogs.com/sto324/p/11297438.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值