題解 SP3693 【KGSS - Maximum Sum】
阿新 • • 發佈:2020-08-19
題目連結: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; }
本蒟蒻的第二篇題解,求各位點個讚唄。