1. 程式人生 > 實用技巧 >題解 SP3693 【KGSS - Maximum Sum】

題解 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;
}

本蒟蒻的第二篇題解,求各位點個讚唄。