题解 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; }
本蒟蒻的第二篇题解,求各位点个赞呗。