线段树求最大子段和 9 分求助

P4513 小白逛公园

ncwzdlsd @ 2023-03-10 10:18:46

swap,查询修改貌似也没有问题,样例可过,交上去就 9 分/kk/kel

#include <bits/stdc++.h>
using namespace std;
#define int long long

const int maxn=5e5+5;
int a[maxn];

struct node
{
    int ls,rs,ml,mr,ans,sum;
//  maxleft,maxright,maxvalue,最大子段和,区间和 
}t[maxn];

void merge(int k)//合并区间统计答案 
{
    t[k].sum=t[k*2].sum+t[k*2+1].sum;
    t[k].ml=max(t[k*2].ml,t[k*2].sum+t[k*2+1].mr);//左区间最大子段和、左区间和+右区间左区间最大子段和
    t[k].mr=max(t[k*2+1].mr,t[k*2].ml+t[k*2+1].sum);
    t[k].ans=max(max(t[k*2].ans,t[k*2+1].ans),t[k*2].mr+t[k*2+1].ml/*横跨左右区间*/);
}

void build(int k,int l,int r)
{
    t[k].ls=l;t[k].rs=r;
    if(l==r) {t[k].sum=t[k].ml=t[k].mr=t[k].ans=a[l];return;}
    int mid=(l+r)/2;
    build(k*2,l,mid);build(k*2+1,mid+1,r);
    merge(k);
}

//OK 
void change(int k,int x,int y) 
{
    if(t[k].ls==t[k].rs)  {t[k].ml=t[k].mr=t[k].ans=t[k].sum=y;return;}
    int mid=(t[k].ls+t[k].rs)/2;
    if(x<=mid) change(k*2,x,y);
    else change(k*2+1,x,y);
    merge(k);//值改变,重新合并 
}

node query(int k,int l,int r)
{
    if(l<=t[k].ls&&r>=t[k].rs) return t[k];
    int mid=(t[k].ls+t[k].rs)/2;
    if(r<=mid) return query(k*2,l,r);//只在左区间 
    else if(l>mid) return query(k*2+1,l,r);//只在右区间 
    else
    {
        node aa=query(k*2,l,r),bb=query(k*2+1,l,r),nw/*合并操作*/;
        nw.sum=aa.sum+bb.sum;
        nw.ml=max(aa.ml,aa.sum+bb.ml);
        nw.mr=max(bb.mr,bb.sum+aa.mr);
        nw.ans=max(max(aa.ans,bb.ans),aa.mr+bb.ml);
        return nw; 
    }
}

signed main()
{
    int n,m;cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    build(1,1,n); 
    while(m--)
    {
        int k;cin>>k;
        if(k==1)
        {
            int a,b;cin>>a>>b;
            if(a>b) swap(a,b);
            cout<<query(1,a,b).ans<<endl;
        }
        else 
        {
            int p,s;cin>>p>>s;
            change(1,p,s);
        }
    }
    return 0;
}

by ncwzdlsd @ 2023-03-10 10:22:19

merge 手残写错了,此帖结


|