zoukankan      html  css  js  c++  java
  • P4513 最大连续字段和 (线段树+区间合并)

    题目链接:https://www.luogu.org/problem/P4513

    题目大意:单点修改和求区间最大连续字段和

    解题思路:很容易想到是用线段树来做,但是如何进行维护呢?

    每个维护区间 [L,R]的节点内我们需要维护以下信息:

    sum:[L,R]的区间和

    lm:从左端点 L开始的最大子段和(简称左子段和)

    rm:从右端点 R 开始的最大子段和(简称右子段和)

    ans:[L,R] 内的最大子段和

    注意:询问区间跨过mid时要合并一下答案,思路与pushup函数中的差不多

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=500000+7;
    int n,m,a[maxn];
    struct node{
        int lm,rm,sum,ans;
    }tree[maxn*4];
    void pushup(int rt){
        tree[rt].lm=max(tree[rt<<1].lm,tree[rt<<1].sum+tree[rt<<1|1].lm);
        tree[rt].rm=max(tree[rt<<1|1].rm,tree[rt<<1|1].sum+tree[rt<<1].rm);
        tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum;
        tree[rt].ans=max(max(tree[rt<<1].ans,tree[rt<<1|1].ans),tree[rt<<1].rm+tree[rt<<1|1].lm);
    }
    void build(int l,int r,int rt){
        if(l==r){
            tree[rt].lm=tree[rt].rm=tree[rt].sum=tree[rt].ans=a[l];
            return;
        }
        int mid=(l+r)>>1;
        build(l,mid,rt<<1);
        build(mid+1,r,rt<<1|1);
        pushup(rt);
    }
    void update(int pos,int val,int l,int r,int rt){
        if(l==r){
            tree[rt].lm=tree[rt].rm=tree[rt].sum=tree[rt].ans=val;
            return;
        }
        int mid=(l+r)>>1;
        if(pos<=mid) update(pos,val,l,mid,rt<<1);
        else update(pos,val,mid+1,r,rt<<1|1);
        pushup(rt);
    }
    node query(int L,int R,int l,int r,int rt){
        if(L<=l&&R>=r) return tree[rt];  //区间完全覆盖,直接返回该节点
        int mid=(l+r)>>1;
        if(R<=mid) return query(L,R,l,mid,rt<<1);  //只在左区间,直接查询左区间
        else if(L>mid) return query(L,R,mid+1,r,rt<<1|1); //只在右区间,直接查询右区间
        else{ //左右区间都有,考虑如何合并
        //res1记录左覆盖区间,res2记录右覆盖区间
            node res,res1=query(L,mid,l,mid,rt<<1),res2=query(mid+1,R,mid+1,r,rt<<1|1);
            res.lm=max(res1.lm,res1.sum+res2.lm);
            res.rm=max(res2.rm,res2.sum+res1.rm);
            res.ans=max(max(res1.ans,res2.ans),res1.rm+res2.lm);
            return res;
        }
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        build(1,n,1);
        while(m--){
            int op,x,y;
            scanf("%d%d%d",&op,&x,&y);
            if(op==1){
                if(x>y) swap(x,y);
                printf("%d
    ",query(x,y,1,n,1).ans);
            }else update(x,y,1,n,1);
        }
        return 0;
    }
  • 相关阅读:
    [状压dp][spfa] Jzoj P3737 挖宝藏
    [计算几何] Jzoj P3736 数学题
    [排序][vector] Jzoj P6288 旋转子段
    [区间dp] Jzoj P6287 扭动的树
    [bfs][spfa] Jzoj P6286 走格子
    [点分治] Luogu P2664 树上游戏
    [树链剖分][树状数组] Luogu P3676 小清新数据结构题
    [计算几何][dp] Luogu P1995 智能车比赛
    [后缀数组][并查集] Luogu P2178 品酒大会
    [莫比乌斯反演][整除分块] Bzoj P2301 Problem b
  • 原文地址:https://www.cnblogs.com/zjl192628928/p/11438270.html
Copyright © 2011-2022 走看看