DestinHistoire

 

BZOJ-1756 Vijos1083 小白逛公园(线段树维护最大子段和)

题目描述

  给定长为 \(n(1\leq n\leq 5\times 10^5)\) 的序列 \(a\),以及 \(m(1\leq m\leq 10^5)\) 次操作,有两种操作:

  操作 \(1\)1 l r,查询区间 \([l,r]\) 中的最大连续子段和,即 \(\max\limits_{l\leq x\leq y\leq r}\Big\{\displaystyle\sum_{i=x}^{y}a[i]\Big\}\)

  操作 \(2\)2 x v,把 \(a[x]\) 修改成 \(v\)

  对于每个操作 \(1\),输出一个整数表示答案。

分析

  在线段树的每个节点中除了区间左右端点外再维护 \(4\) 个信息:区间和 \(sum\),区间最大连续子段和 \(dat\),紧靠左端的最大连续子段和 \(lmax\),紧靠右端的最大连续子段和 \(rmax\)

  在 \(build\)\(update\) 函数中从下往上传递信息:

tree[p].sum=tree[p*2].sum+tree[p*2+1].sum;
tree[p].lmax=max(tree[p*2].lmax,tree[p*2].sum+tree[p*2+1].lmax);
tree[p].rmax=max(tree[p*2+1].rmax,tree[p*2+1].sum+tree[p*2].rmax);
tree[p].dat=max(tree[p*2].dat,tree[p*2+1].dat,tree[p*2].lmax+tree[p*2+1].rmax);

  在询问最大连续子段和时需要通过合并区间来更新答案,因为最大连续子段和的区间可能不是线段树的一个节点(即无法通过查找左右儿子访问),所以函数返回类型是结构体的节点而不是值。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int n,m,a[N];
struct SegmentTree
{
    int l,r;
    int sum,dat;
    int lmax,rmax;
}tree[N<<2];
void pushup(int p)
{
    tree[p].sum=tree[p*2].sum+tree[p*2+1].sum;
    tree[p].lmax=max(tree[p*2].lmax,tree[p*2].sum+tree[p*2+1].lmax);
    tree[p].rmax=max(tree[p*2+1].rmax,tree[p*2+1].sum+tree[p*2].rmax);
    tree[p].dat=max(max(tree[p*2].dat,tree[p*2+1].dat),tree[p*2].rmax+tree[p*2+1].lmax);
}
void build(int p,int l,int r)
{
    tree[p].l=l;tree[p].r=r;
    if(l==r)
    {
        tree[p].dat=a[l];
        tree[p].sum=a[l];
        tree[p].lmax=a[l];
        tree[p].rmax=a[l];
        return ;
    }
    int mid=(l+r)/2;
    build(p*2,l,mid);
    build(p*2+1,mid+1,r);
    pushup(p);
}
void update(int p,int x,int val)
{
    if(tree[p].l==tree[p].r)
    {
        tree[p].sum=val;
        tree[p].lmax=val;
        tree[p].rmax=val;
        tree[p].dat=val;
        return ;
    }
    int mid=(tree[p].l+tree[p].r)/2;
    if(x<=mid)
        update(p*2,x,val);
    else
        update(p*2+1,x,val);
    pushup(p);
}
SegmentTree query(int p,int l,int r)
{
    if(l<=tree[p].l&&tree[p].r<=r)
        return tree[p];
    int mid=(tree[p].l+tree[p].r)/2;
    if(r<=mid)
        return query(p*2,l,r);
    if(l>mid)
        return query(p*2+1,l,r);
    SegmentTree a,b,ans;
    a=query(p*2,l,r);b=query(p*2+1,l,r);
    ans.sum=a.sum+b.sum;
    ans.lmax=max(a.lmax,a.sum+b.lmax);
    ans.rmax=max(b.rmax,a.rmax+b.sum);
    ans.dat=max(max(a.dat,b.dat),a.rmax+b.lmax);
    return ans;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    build(1,1,n);
    while(m--)
    {
        int op;
        scanf("%d",&op);
        if(op==2)
        {
            int x,v;
            scanf("%d %d",&x,&v);
            update(1,x,v);
        }
        if(op==1)
        {
            int l,r;
            scanf("%d %d",&l,&r);
            if(l>r)
                swap(l,r);
            printf("%d\n",query(1,l,r).dat);
        }
    }
    return 0;
}

posted on 2020-11-25 15:38  DestinHistoire  阅读(66)  评论(0)    收藏  举报

导航