小白逛公园题解-编程学习交流讨论版论坛-综合讨论-ZDZL
AI 文章摘要
本文介绍了如何用线段树解决“小白逛公园”问题(洛谷P4513),核心是实现支持**单点修改**和**查询区间最大子段和**的数据结构。 **要点**: 1. 线段树节点需维护四个值:区间和、从左端开始的最大子段和、从右端开始的最大子段和、整个区间的最大子段和。 2. 区间最大子段和可能完全在左子树、完全在右子树或跨越左右子树,合并时需综合计算。 3. 通过递归建树、单点更新和区间查询操作实现功能,无需懒标记。 4. 提供了完整的C++代码实现,包括建树、查询与更新函数。

小白逛公园题解

不知道博客能不能写题解,我来试试。

一道版蓝。

P4513

题目大意

现在有两种操作:

  1. 输出区间为 a,b 的最大子段和
  2. 将第 p 个公园的打分变为 s

思路

我们知道本题需要在区间和线段树的前提下维护最大子段和。我们发现某区间的最大值有以下三种情况

  1. 全部位于左孩子
  2. 全部位于右孩子
  3. 两边都有

那么我们可以在线段树结构体的基础上再开三个变量,即从左边开始的最大子段和,从右边开始的最大子段和,整个区间的最大子段和。那么代码易得。注意我们要把懒标记扔进旁边的垃圾桶。

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=4000005;
vector<int> a(N);
class segment_tree{
    private:
        struct node{
            int data,l,r,maxx;
        }tree[N];
        int left_child(int now){//取左孩子,返回的是索引
            return 2*now;
        }int right_child(int now){//取右孩子
            return 2*now+1;
        }void pushup(int now){//这里方便一点写了一个 pushup
            tree[now].data=tree[left_child(now)].data+tree[right_child(now)].data;
            tree[now].maxx=max(tree[left_child(now)].maxx,max(tree[left_child(now)].r+tree[right_child(now)].l,tree[right_child(now)].maxx));
            tree[now].l=max(tree[left_child(now)].l,tree[left_child(now)].data+tree[right_child(now)].l);
            tree[now].r=max(tree[right_child(now)].r,tree[right_child(now)].data+tree[left_child(now)].r);
        }
    public:
        void build(int now,int l,int r){//递归建树
            if(l==r){//叶子节点
                tree[now].data=tree[now].l=tree[now].r=tree[now].maxx=a[l];
                return ;
            }int mid=l+(r-l)/2;
            build(left_child(now),l,mid);build(right_child(now),mid+1,r);//分别递归左半边和右半边
            pushup(now);
        }
        node query_add(int now,int l,int r,int ql,int qr){//求区间和函数。分别为当前节点,左区间,右区间,所求区间的左右区间
            if(ql<=l and qr>=r)return tree[now];
            int mid=l+(r-l)/2;
            node ml,mr,ans;
            if(qr<=mid)return query_add(left_child(now),l,mid,ql,qr);
            if(ql>mid)return query_add(right_child(now),mid+1,r,ql,qr);
            ml=query_add(left_child(now),l,mid,ql,qr);
            mr=query_add(right_child(now),mid+1,r,ql,qr);
            ans.data=ml.data+mr.data;
            ans.maxx=max(ml.maxx,max(mr.maxx,ml.r+mr.l));
            ans.l=max(ml.l,ml.data+mr.l);
            ans.r=max(mr.r,mr.data+ml.r);
            return ans;
        }
        void update(int now,int l,int r,int idx,int val){//单点更新
            if(l==r){
                tree[now]={val,val,val,val};
                return ;
            }int mid=l+(r-l)/2;
            if(mid>=idx){
                update(left_child(now),l,mid,idx,val);
            }else{
                update(right_child(now),mid+1,r,idx,val);
            }pushup(now);
        }
};
signed main(){
    segment_tree tree;
    int n,m;
    cin >> n >> m;
    for(int i=1;i<=n;i++){
        cin >> a[i];
    }tree.build(1,1,n);
    while(m--){
        int op,x,y;
        cin >> op;
        cin >> x >> y; 
        
        if(op==1){
            if(x>y)swap(x,y);
            cout << tree.query_add(1,1,n,x,y).maxx << endl;
        }
        else tree.update(1,1,n,x,y);
    }
    return 0;
}