AcWing 245. 你能回答这些问题吗

AcWing 245. 你能回答这些问题吗

给定长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:

1、“1 x y”,查询区间 [x,y] 中的最大连续子段和,即 maxx≤l≤r≤y{∑ri=lA[i]}。

2、“2 x y”,把 A[x] 改成 y。

对于每个查询指令,输出一个整数表示答案。

输入格式
第一行两个整数N,M。

第二行N个整数A[i]。

接下来M行每行3个整数k,x,y,k=1表示查询(此时如果x>y,请交换x,y),k=2表示修改。

输出格式
对于每个查询指令输出一个整数表示答案。

每个答案占一行。

数据范围
N≤500000,M≤100000,
−1000≤A[i]≤1000
输入样例:

5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 3 2

输出样例:

2
-1

这道题求的是l-r的最大连续区间和,我刚开始想到用dp去做o(n)级别的,但是没想到的是,这是一个动态变化的最大连续区间和,我就在想怎么去做呢。(我也是刚开始设计线段树),于是我就仔细地看了一遍y总的视频。

首先我们要开始build
我了解到线段树一定要保证完备性,y总提出了左右两个子树怎么求最大区间和的方法。
AcWing 245. 你能回答这些问题吗_第1张图片
最大区间和我们求出来了,但是我们的最大前缀和最大后缀怎么求呢?
接下来是最大前缀的求解方法(最大后缀同理)。
根节点最大前缀等于max(左节点的最大前缀,左节点的和+右边的最大前缀)
AcWing 245. 你能回答这些问题吗_第2张图片
sum操作就很简单了,左子树的sum+右子树的sum

最后实现query操作。
query操作我觉得学起来是最细节也是最难理解的地方
首先query返回的不是一个树,因为进行左右子树确定最大连续区间和需要(sum,lmax,rmax)这三个数,所以我们就把返回值变成struct这样就很容易轻松的进行一个pushup的操作返回我们想要得到的答案。

Node query(int u,int l,int r)
{
        if(l<=tr[u].l&&tr[u].r<=r) return tr[u];
        else
        {
        int mid=tr[u].l+tr[u].r>>1;
        if(r<=mid) return query(u<<1,l,r);
        else if(l>mid) return query(u<<1|1,l,r);
        else
        {
            auto left=query(u<<1,l,r);
            auto right=query(u<<1|1,l,r);
            Node res;
            pushup(res,left,right);
            return res;
        }
        }
}

最终代码如下:

#include
#include

using namespace std;

const int N=5e5+10;

struct Node
{
    int l,r;
    int sum;
    int rmax;
    int lmax;
    int tmax;
} tr[N*4];
int w[N];
int n,m;

void pushup(Node &root,Node &l,Node &r)
{
    root.sum=l.sum+r.sum;
    root.rmax=max(r.rmax,r.sum+l.rmax);
    root.lmax=max(l.lmax,l.sum+r.lmax);
    root.tmax=max(max(l.tmax,r.tmax),l.rmax+r.lmax);
}

void pushup(int u)
{
    pushup(tr[u],tr[u<<1],tr[u<<1|1]);
}

void build(int u,int l,int r)
{
    if(l==r)
    {
        tr[u]={l,r,w[l],w[l],w[l],w[l]};
    }
    else
    {
        tr[u]={l,r};
        int mid=l+r>>1;
        build(u<<1,l,mid);
        build(u<<1|1,mid+1,r);
        pushup(u);
    }
}

void modify(int u,int x,int v)
{
    if(tr[u].l==x&&tr[u].r==x) tr[u]={x,x,v,v,v,v};
    else
    {
        int mid=tr[u].l+tr[u].r>>1;
        if(x<=mid) modify(u<<1,x,v);
        else
        modify(u<<1|1,x,v);
        pushup(u);
    }
}

Node query(int u,int l,int r)
{
        if(l<=tr[u].l&&tr[u].r<=r) return tr[u];
        else
        {
        int mid=tr[u].l+tr[u].r>>1;
        if(r<=mid) return query(u<<1,l,r);
        else if(l>mid) return query(u<<1|1,l,r);
        else
        {
            auto left=query(u<<1,l,r);
            auto right=query(u<<1|1,l,r);
            Node res;
            pushup(res,left,right);
            return res;
        }
        }
}
int main(void)
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&w[i]);
    build(1,1,n);
    
    while(m--)
    {
        int k;
        scanf("%d",&k);
        if(k==1)
        {
           int a,b;
           scanf("%d%d",&a,&b);
           if(a>b)
           swap(a,b);
           cout<<query(1,a,b).tmax<;
        }
        else
        {
            int x,y;
            scanf("%d%d",&x,&y);
            modify(1,x,y);
        }
    }
}

你可能感兴趣的:(蓝桥杯,A/B组训练(省赛),蓝桥杯,A/B组训练,数据结构-线段树/树状数组)