【单点修改 最大连续子段和】 Can you answer this question

传送门

题意

给定长度为\(n\)的序列\(a\),一共\(m\)条指令,每个指令有两种

  • \((1,x,y)\) ,查询区间\([x,y]\)的最大子序列和
  • \((2,x,y)\) ,将\(a[x]\)的值改成\(y\)

对于每个查询输出整数答案

数据范围

\(1\leq N \leq 500000\)
$ 1\leq M \leq 100000$

题意

维护的属性有

  • \(mx\):当前区间内部的最大连续子段和
  • \(lmax\):紧靠当前区间左端的最大连续子段和
  • \(rmax\):紧靠当前区间右端的最大连续子段和
  • \(sum\):当前区间和

当前节点的区间中最大连续和从三种情况中取得

  • \(l.mx\)
  • \(r.mx\)
  • \(l.rmax+r.lmax\)

\(lmax\)从以下两种情况中取最大值

  • \(lmax\)完全在左半边
  • \(lmax\)是左边\(sum\)加右边\(lmax\)

\(rmax\)从以下两种情况中取最大值

  • \(rmax\)完全在右半边
  • \(rmax\)是左边的\(rmax\)加右边的\(sum\)

所以要维护一个\(sum\),便于计算左右的连续子段和
查询可能存在的坑点:左右端点相反

  • \(build\)时就会将线段树的左端点划入区间的子段,所以在查询时递归进入左子树的需要取等号

Code

#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, n) for(int i = a; i < n; i ++)
const int N = 5e5 + 10;

int n, m;
int a[N];

struct node
{
    int l, r;
    int sum;
    int lmax, rmax;
    int mx;
    #define l(u) u * 2
    #define r(u) u * 2 + 1
}tr[N * 4];

void pushup(node &root, node &left, node &right)
{
    root.sum = left.sum + right.sum;
    root.lmax = max(left.lmax, left.sum + right.lmax);
    root.rmax = max(right.rmax, right.sum + left.rmax);
    root.mx = max(max(left.mx, right.mx), left.rmax + right.lmax);
}
void pushup(int u)
{
    pushup(tr[u], tr[l(u)], tr[r(u)]);
}
void build(int u, int l, int r)
{
    if(l == r)
        tr[u] = {l, r, a[l], a[l], a[l], a[l]};
    else
    {
        tr[u].l = l; tr[u].r = r;
        int mid = l + r >> 1;
        build(l(u), l, mid);
        build(r(u), mid + 1, r);
        pushup(u);
    }
}
void modify(int u, int x, int y)
{
    if(tr[u].l == x && tr[u].r == x)
        tr[u]={x, x, y, y, y, y};
    else
    {
        int mid = tr[u].l + tr[u].r >> 1;
        if(x <= mid) modify(l(u), x, y);
        else modify(r(u), x, y);
        pushup(u);
    }
}
node query(int u, int l, int r)
{   
    if(tr[u].l >= l && tr[u].r <= r)
        return tr[u];
    int mid = tr[u].l + tr[u].r >> 1;
    if(l > mid) return query(r(u), l, r);
    if(r <= mid) return query(l(u), l, r);
    else 
    {
        node left = query(l(u), l, r);
        node right = query(r(u), l, r);
        node res;
        pushup(res, left, right);
        return res;
    }
}
int main()
{
    cin>>n>>m;
    rep(i, 1, n+1) cin>>a[i];

    build(1,1,n);

    int op, x, y;
    while(m --)
    {
        cin>>op>>x>>y;
        if(op == 1)
        {
            if(x > y) swap(x, y);
            cout<<query(1, x, y).mx<<endl;
        }
        else 
            modify(1, x, y);    
    }   
}
posted @ 2020-05-22 02:13  Hyx'  阅读(153)  评论(0)    收藏  举报