题解 SP3693 【KGSS - Maximum Sum】

题目链接:link

由于刚学了线段树所以就用了线段树做。

推荐先去做一下线段树模板,link

首先来大致了解一下线段树:
线段树,类似区间树,它在各个节点保存一条线段(数组中的一段子数组),主要用于高效解决连续区间的动态查询问题,由于二叉结构的特性,它基本能保持每个操作的复杂度为 O(logn) 。

线段树的每个节点表示一个区间,子节点则分别表示父节点的左右半区间,例如父亲的区间是 [a,b] ,那么 (c=(a+b)/2) 左儿子的区间是 [a,c] ,右儿子的区间是 [c+1,b] 。


建树

struct tree{
    int ma,xm;//由于本题要求,ma和xm分别代表最大值和次大值
}t[500100];
inline void change(int p){
    int ls=p<<1,rs=p<<1|1;
    t[p].ma=max(t[ls].ma,t[rs].ma);
    if(t[ls].ma>t[rs].ma)t[p].xm=max(t[ls].xm,t[rs].ma);
    else t[p].xm=max(t[ls].ma,t[rs].xm);
}
inline void build(int p,int ls,int rs){
    if(ls==rs){//叶子节点
        t[p].ma=val[ls];
        return;
    }
    int mid=ls+rs>>1;
    build(p<<1,ls,mid);//构建左子树
    build(p<<1|1,mid+1,rs);//右子树
    change(p);//根据左右子树根节点的值,更新当前根节点的值
}

单点修改

inline void modify(int p,int ls,int rs){
    if(ls==rs){//找到了相应的节点,更新
        t[p].ma=c;
        return;
    }
    int mid=ls+rs>>1;
    if(z<=mid)modify(p<<1,ls,mid);//在左子树中更新
    else modify(p<<1|1,mid+1,rs);//在右子树中更新
    change(p);//根据左右子树的值回溯更新当前节点的值
}

区间查询最大值和次大值

inline void judge(int &a,int b){
    if(a<b)a=b;//更新
}

inline void query(int p,int ls,int rs){
    if(l<=ls&&r>=rs){//当前节点区间包含在查询区间内
        if(t[p].ma>ans1){
            judge(ans2,ans1);//比较大小,记录并更新
            ans1=t[p].ma;
            judge(ans2,t[p].xm);
        }
        else judge(ans2,t[p].ma);
        return;
    }
    int mid=ls+rs>>1;
    if(l<=mid)query(p<<1,ls,mid);//查询左子树
    if(r>mid)query(p<<1|1,mid+1,rs);//右子树
}

 完整代码

#include"cstdio"
#define rint register int
inline int read(){
    int p=0,w=1;
    char c=getchar();
    while(c>'9'||c<'0'){
        if(c=='-')w=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        p=p*10+c-'0';
        c=getchar();
    }
    return p*w;
}
inline int max(int a,int b){
    return (a>b)?a:b;
}
inline void judge(int &a,int b){
    if(a<b)a=b;
}
inline int quest(){
    char c=getchar();
    while(c!='U'&&c!='Q')c=getchar();
    if(c=='U')return 0;
    else return 1;
}
int val[500100],ans1,ans2,n,m;
int l,r,z,c;
struct tree{
    int ma,xm;
}t[500100];
inline void change(int p){
    int ls=p<<1,rs=p<<1|1;
    t[p].ma=max(t[ls].ma,t[rs].ma);
    if(t[ls].ma>t[rs].ma)t[p].xm=max(t[ls].xm,t[rs].ma);
    else t[p].xm=max(t[ls].ma,t[rs].xm);
}
inline void build(int p,int ls,int rs){
    if(ls==rs){
        t[p].ma=val[ls];
        return;
    }
    int mid=ls+rs>>1;
    build(p<<1,ls,mid);
    build(p<<1|1,mid+1,rs);
    change(p);
}
inline void modify(int p,int ls,int rs){
    if(ls==rs){
        t[p].ma=c;
        return;
    }
    int mid=ls+rs>>1;
    if(z<=mid)modify(p<<1,ls,mid);
    else modify(p<<1|1,mid+1,rs);
    change(p);
}
inline void query(int p,int ls,int rs){
    if(l<=ls&&r>=rs){
        if(t[p].ma>ans1){
            judge(ans2,ans1);
            ans1=t[p].ma;
            judge(ans2,t[p].xm);
        }
        else judge(ans2,t[p].ma);
        return;
    }
    int mid=ls+rs>>1;
    if(l<=mid)query(p<<1,ls,mid);
    if(r>mid)query(p<<1|1,mid+1,rs);
}
int main(){
    n=read();
    for(rint i=1;i<=n;i++)val[i]=read();
    build(1,1,n);
    m=read();
    while(m--){
        int op=quest();
        if(op){
            ans1=-100000,ans2=-200000;//记得更新ans的值
            l=read(),r=read();
            query(1,1,n);
            printf("%d\n",ans1+ans2);
        }
        else{
            z=read(),c=read();
            modify(1,1,n);
        }
    }
    return 0;
}

本蒟蒻的第二篇题解,求各位点个赞呗。

posted @ 2020-08-19 18:33  Nakiri_Ayame_suki  阅读(409)  评论(0编辑  收藏  举报