最大子段和之单点修改,区间查询

单点修改,区间查询的最大子段和

题目模型

  • 我们对问题进行扩展,如果对序列有两种操作:

    1. 修改序列的某个元素的值
    2. 查询序列\([l,r]\)的区间和。
  • 题目模型见P4513 小白逛公园

问题分析

  • 单点修改,区间查询显然要用线段树。
  • 类似上面分治,区间最大字段和有三种情况:
    1. 最大子段和在左子树。
    2. 最大子段和在右子树。
    3. 左子树的最大后缀和+右子树的最大前缀和。

代码实现

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+10;
#define lson l,mid,(rt<<1)
#define rson mid+1,r,(rt<<1|1)
struct Tree{
    int presum,sufsum,sub,sum;//presum为当前区间最大前缀和,sufsum为当前区间最大后缀和,sub为当前区间最大子段和,sum为当前区间的和
}tree[maxn<<2];
Tree pushup(Tree l,Tree r){//合并左右两区间
    Tree rt;
    rt.presum=max(l.presum,l.sum+r.presum);//当前区间的最大前缀和:左子树的最大前缀和 or 左子树的和+右子树的最大前缀和
    rt.sufsum=max(r.sufsum,r.sum+l.sufsum);//当前区间的最大后缀和:右子树的最大后缀和 or 右子树的和+左子树的最大后缀和
    rt.sub=max(max(l.sub,r.sub),l.sufsum+r.presum);//当前区间的最大子段和:左子树的最大子段和 or 右子树的最大子段和 or 左子树的最大后缀和+右子树的最大前缀和
    rt.sum=l.sum+r.sum;//当前区间的和:左子树的和+右子树的和
    return rt;
}
void build(int l,int r,int rt){
    if(l==r){
        scanf("%d",&tree[rt].sum);
        tree[rt].presum=tree[rt].sufsum=tree[rt].sub=tree[rt].sum;
        return ;
    }
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
    tree[rt]=pushup(tree[rt<<1],tree[rt<<1|1]);
}
void update(int pos,int w,int l,int r,int rt){//把pos个元素修改成值w
    if(l==r){
        tree[rt].presum=tree[rt].sufsum=tree[rt].sub=tree[rt].sum=w;
        return ;
    }
    int mid=(l+r)>>1;
    if(pos<=mid) update(pos,w,lson);
    if(pos> mid) update(pos,w,rson);
    tree[rt]=pushup(tree[rt<<1],tree[rt<<1|1]);
}
Tree query(int L,int R,int l,int r,int rt){
    if(L<=l&&r<=R)
        return tree[rt];
    int mid=(l+r)>>1;
    Tree ret,lret,rret;
    int flag1=0,flag2=0;//flag1标记区间[L,R]是否在rt的左子树,flag2右子树
    if(L<=mid) {lret=query(L,R,lson);flag1=1;}
    if(R> mid) {rret=query(L,R,rson);flag2=1;}

    if(flag1&&flag2) ret=pushup(lret,rret);//左右子树均有就合并计算
    else if(flag1) ret=lret;//只在左子树
    else if(flag2) ret=rret;//只在右子树
    return ret;
}
void Solve(){
	int n,m;scanf("%d%d",&n,&m);
    build(1,n,1);
    for(int i=1;i<=m;i++){
        int op;
        scanf("%d",&op);
        if(op==1){
            int l,r;
            scanf("%d%d",&l,&r);
            if(l>r) swap(l,r);
            Tree ans=query(l,r,1,n,1);
            printf("%d\n",ans.sub);
        }
        else{
            int p,s;
            scanf("%d%d",&p,&s);
            update(p,s,1,n,1);
        }
    }
}
int main(){
    Solve();
    return 0;
}
posted @ 2020-06-15 14:46  ♞老姚♘  阅读(350)  评论(0编辑  收藏  举报