最大连续子段和求助

P4513 小白逛公园

NirvanaCeleste @ 2024-11-22 22:06:48

#include <bits/stdc++.h>
using namespace std;
const int maxn = 500100;
void read(int &x){
    int y=0,w=1;
    char ch=getchar();
    while(ch < '0' || ch > '9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch >= '0' && ch <= '9'){y=y*10+ch-'0';ch=getchar();}
    x=y*w;
}
void write(int x){
    if(x < 0) x=-x,putchar('-');
    if(x > 9) write(x/10);
    putchar(x%10+'0');
}
int n,m;
int a[maxn];
struct node{
    int sum,ans,maxl,maxr;
}t[maxn*4];
inline int ls(int p){return p<<1;}
inline int rs(int p){return p<<1|1;} 
inline void pushup(int p){
    t[p].sum = t[ls(p)].sum + t[rs(p)].sum;
    t[p].maxl = max(t[ls(p)].maxl,t[ls(p)].sum + t[rs(p)].maxl);
    t[p].maxr = max(t[rs(p)].maxr,t[rs(p)].sum + t[ls(p)].maxr);
    t[p].ans = max(t[ls(p)].maxl,t[rs(p)].maxr);
    t[p].ans = max(t[p].ans,t[ls(p)].maxr + t[rs(p)].maxl);
    t[p].ans = max(t[p].ans,t[ls(p)].sum + t[rs(p)].maxl);
    t[p].ans = max(t[p].ans,t[rs(p)].sum + t[ls(p)].maxr);
    t[p].ans = max(t[p].ans,t[ls(p)].ans);//
    t[p].ans = max(t[p].ans,t[rs(p)].ans);//
}
inline void nodeadd(int p,int k){
    t[p].sum += k;
    t[p].maxl += k;
    t[p].maxr += k;
    t[p].ans += k;
}
void build(int p,int l,int r){
    if(l == r){
        nodeadd(p,a[l]);
        return;
    }
    int mid = (l+r)>>1;
    build(ls(p),l,mid);
    build(rs(p),mid+1,r);
    pushup(p);
}
int ask(int p,int l,int r,int nl,int nr){
    int res = INT_MIN;
    if(nl <= l && r <= nr || l == r) return t[p].ans;
    int mid = (l + r) >> 1;
    if(mid < nr) res = max(res,ask(rs(p),mid+1,r,nl,nr));
    if(mid >= nl) res = max(res,ask(ls(p),l,mid,nl,nr));
    return res;
}
void add(int p,int l,int r,int x,int k){
    if(l == r){
        nodeadd(p,k);
        return;
    }
    int mid = (l + r) >> 1;
    if(mid < x) add(rs(p),mid+1,r,x,k);
    if(mid >= x) add(ls(p),l,mid,x,k);
    pushup(p);
}
int main(){
    read(n),read(m);
    for(int i=1;i<=n;i++) read(a[i]);
    build(1,1,n);
    int k,x,y;
    while(m--){
        read(k),read(x),read(y);
        if(k == 1){
            if(x > y) swap(x,y);
            write(ask(1,1,n,x,y)),putchar('\n');
        }
        if(k == 2) add(1,1,n,x,y-a[x]),a[x]=y;
    }
    return 0;
}

by chenxi2009 @ 2024-11-23 09:55:58

@NirvanaCeleste 单点 maxl maxr 不是这个点的值,应该是这个点和 0 取 max。


by chenxi2009 @ 2024-11-23 09:59:03

sry,搞错了。


by chenxi2009 @ 2024-11-23 10:08:14

@NirvanaCeleste 询问时的答案返回不对,有可能既不是左边、右边区间的最大值,还有可能是左右两边各取一点。建议询问操作改成结构体类型。


by NirvanaCeleste @ 2024-11-23 10:13:45

@chenxi2009 一段区间的最大连续子段和是不是可能来自以下五种情况:

1. |++++++------|-----------|
2. |------------|------+++++|
3. |++++++++++++|++++-------|
4. |--------++++|+++++++++++|
5. |--------++++|++++-------|

by NirvanaCeleste @ 2024-11-23 10:14:33

@chenxi2009 第五种情况是不是左右两边各取一点的情况


by NirvanaCeleste @ 2024-11-23 10:15:49

pushup中第五行

t[p].ans = max(t[p].ans,t[ls(p)].maxr + t[rs(p)].maxl);

是否对应这种情况


by chenxi2009 @ 2024-11-23 10:16:27

@NirvanaCeleste 对,询问时可能取了很多个区间(如 [7,7],[8,16],[17,18]),这个时候合并就不再是常规方式的合并(取 Max)。


by chenxi2009 @ 2024-11-23 10:17:21

@NirvanaCeleste 对的。建议写一个结构体区间合并函数,同时代替 pushup 和询问合并。


by NirvanaCeleste @ 2024-11-23 10:17:47

sry 我明白了 pushup没写错 是不是ask写错了


by NirvanaCeleste @ 2024-11-23 10:24:28

@chenxi2009 可以这样理解 ask中只考虑了左右两个区间分开的答案 如

|---+++++---|--++++++---|

但是没有考虑 两端小区间可以合并的情况

|------+++|+++++---|

这种只会返回左右两者的较大值

感谢 以关 qwq


|