zoukankan      html  css  js  c++  java
  • 最大子段和之单点修改,区间查询

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

    题目模型

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

      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
    ",ans.sub);
            }
            else{
                int p,s;
                scanf("%d%d",&p,&s);
                update(p,s,1,n,1);
            }
        }
    }
    int main(){
        Solve();
        return 0;
    }
    
  • 相关阅读:
    Python爬虫案例:爬取微信公众号文章
    MySQL计算两坐标距离并排序
    删库了一定要跑路吗?
    在python中列表删除和多重循环退出
    软件设计模式修炼 -- 观察者模式
    C# WPF:快把文件从桌面拖进我的窗体来!
    C#(七)基础篇—基本I/O操作
    (8)ASP.NET Core3.1 Ocelot Consul服务注册与发现
    iNeuOS工业互联操作系统,图表与数据点组合成新组件,进行项目复用
    对于经常接触的分页你确定你真的会吗
  • 原文地址:https://www.cnblogs.com/hbhszxyb/p/13130882.html
Copyright © 2011-2022 走看看