题解 | 《算法竞赛进阶指南》 你能回答这些问题吗(三)

【题目】

给定长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:
“1 x y”,查询区间 [x,y] 中的最大连续子段和,即 m a x x l r y ( r i = l r A [ i ] ) max_{x \leq l \leq r \leq y}({\sum_{r_i=l}^{r}A[i]})

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

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

【题解】

刚开始看的时候,单点更新,区间修改,第一反应就是线段树,但问题就出在求最大连续子段和,这是个麻烦的事情。而解决这个的方法,就是在线段树中放四个值 a n s l m a x r m a x d a t ans、lmax、rmax、dat a n s ans 是指在线段树的这个区间内,所有数的和, l m a x lmax 指的是这个区间内从最左边开始连续的最大子段和, r m a x rmax 指的是这个区间内从最右边开始的最大子段和, d a t dat 则指的是这个区间内中间最大子段和(跟 l m a x lmax r m a x rmax 不同的地方就在于可以不是从极端开始连续)。这么设计线段树,是因为线段树本身具有的特性形成的,从线段树的最底层想想看,是不是每次跟左兄弟姐妹和右兄弟姐妹的合并:

都是 f a t h e r . l m a x = m a x ( l e f t . l m a x , l e f t . a n s + r i g h t . l e f t ) father.lmax=max(left.lmax,left.ans+right.left) ,进而的求出 f a t h e r . l m a x father.lmax 的最优值,
又都是 f a t h e r . r m a x = m a x ( r i g h t . r m a x , r i g h t . a n s + l e f t . r m a x ) father.rmax=max(right.rmax,right.ans+left.rmax) ,进而的求出 f a t h e r . r m a x father.rmax 的最优值,
又都是 f a t h e r . d a t = m a x ( l e f t . d a t , m a x ( r i g h t . d a t , l e f t . r m a x + r i g h t . l m a x ) ) father.dat=max(left.dat,max(right.dat,left.rmax+right.lmax)) ,进而的求出 f a t h e r . d a t father.dat 的最优值。

那么到了最后,是不是整个线段树的所有的区间只要 m a x ( l m a x r m a x d a t ) max(lmax、rmax、dat) 就能找到这个区间的最大值。当然查询的过程中,还是需要合并被分开来的区间的,这个的话,可以看看我的线段树查询代码。还有就是因为是单点更新,所以不需要懒标记。

时间复杂度:线段树的建树复杂度 O ( N ) O(N) ,查询复杂度 O ( l o g N ) O(logN) ,更新复杂度 O ( l o g N ) O(logN) ,此题整体复杂度 O ( M l o g N ) O(MlogN)

#include<iostream>
#include<cstring>
#include<sstream>
#include<string>
#include<cstdio>
#include<cctype>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#define fi first
#define se second
#define MP make_pair
#define P pair<int,int>
#define PLL pair<ll,ll>
#define Sca(x) scanf("%d",&x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%ld",&x)
#define Scll(x) scanf("%lld",&x)
#define Pri(x) printf("%d\n",x);
#define Prl(x) printf("%lld\n",x);
#define For(i,x,y) for(int i=x;i<=y;i++)
#define _For(i,x,y) for(int i=x;i>=y;i--)
#define FAST_IO std::ios::sync_with_stdio(false)
#define ll long long
const int INF=0x3f3f3f3f;
const ll INFL=0x3f3f3f3f3f3f3f3f;
const double Pi = acos(-1.0);
using namespace std;
template <class T>void tomax(T&a,T b){ a=max(a,b); } 
template <class T>void tomin(T&a,T b){ a=min(a,b); }
const int N=5e5+5;
struct SEG{
    struct Tree{
        int l,r;
        int ans,lmax,rmax,dat;
    }tree[N<<2];
    #define lc (p<<1)
    #define rc ((p<<1)|1)
    #define MID (tree[p].l+tree[p].r)>>1
    void pushup(int p){
        tree[p].ans=tree[lc].ans+tree[rc].ans;
        tree[p].lmax=max(tree[lc].lmax,tree[lc].ans+tree[rc].lmax);
        tree[p].rmax=max(tree[rc].rmax,tree[rc].ans+tree[lc].rmax);
        tree[p].dat=max(tree[lc].dat,max(tree[rc].dat,tree[lc].rmax+tree[rc].lmax));
    }
    void build(int l,int r,int p){
        tree[p].l=l;
        tree[p].r=r;
        tree[p].ans=0;
        if(l==r){
            int x; Sca(x);
            tree[p].ans=tree[p].lmax=tree[p].rmax=tree[p].dat=x;
            return ;
        }
        int mid=MID;
        build(l,mid,lc);
        build(mid+1,r,rc);
        pushup(p);
    }
    void updata(int id,int p,int val){
        if(tree[p].l==id&&tree[p].r==id){
            tree[p].ans=tree[p].lmax=tree[p].rmax=tree[p].dat=val;
            return ;
        }
        int mid=MID;
        if(id<=mid) updata(id,lc,val);
        else updata(id,rc,val);
        pushup(p);
    }
    Tree query(int l,int r,int p){
        if(tree[p].l>=l&&tree[p].r<=r){
            return tree[p];
        }
        int mid=MID;
        if(r<=mid) return query(l,r,lc);
        else if(l>mid) return query(l,r,rc);
        else{
            Tree x,t1=query(l,r,lc),t2=query(l,r,rc);
            x.lmax=max(t1.lmax,t1.ans+t2.lmax);
            x.rmax=max(t2.rmax,t2.ans+t1.rmax);
            x.dat=max(t1.dat,max(t2.dat,t1.rmax+t2.lmax));
            return x;
        }
    }
    int get(int l,int r){
        Tree now=query(l,r,1);
        int maxx=now.lmax;
        tomax(maxx,now.rmax);
        tomax(maxx,now.dat);
        return maxx;
    }
};
SEG go;
int main(){
    int n,m; Sca2(n,m);
    go.build(1,n,1);
    while(m--){
        int op,x,y; Sca3(op,x,y);
        if(op==1){
            if(x>y) swap(x,y);
            Pri(go.get(x,y));
        }
        else go.updata(x,1,y);
    }
}
发布了39 篇原创文章 · 获赞 9 · 访问量 1955

猜你喜欢

转载自blog.csdn.net/qq_36296888/article/details/103113814