【线段树】XIII Open Championship of Y.Kupala Grodno SU Grodno, Saturday, April 29, 2017 Problem J. Jedi Training

题意:给你一个序列,支持两种操作:单点修改;询问一个区间中所有相邻位置下标奇偶性均不同的子序列中,和最大的是多少。

线段树每个结点维护四个值:

以奇数下标开始到奇数下标结束的最大子序列和;

以偶数下标开始到偶数下标结束的最大子序列和;

以奇数下标开始到偶数下标结束的最大子序列和;

以偶数下标开始到奇数下标结束的最大子序列和。

合并的时候先在左右两区间中取较大者,然后奇-偶的答案能通过奇-奇+偶-偶、奇-偶+奇-偶得到;奇-奇的答案能通过奇-奇+偶-奇、奇-偶+奇-奇得到……这样讨论一下。

#include<cstdio>
#include<algorithm>
using namespace std;
int ss[4][2][2];
typedef long long ll;
const ll INF=1000000000000000ll;
int n,m;
struct data{
	ll x[4];
	data(const ll &x,const ll &y,const ll &z,const ll &w){
		this->x[0]=x;
		this->x[1]=y;
		this->x[2]=z;
		this->x[3]=w;
	}
	data(){}
	ll maxx(){
		return max(x[0],max(x[1],max(x[2],x[3])));
	}
};
data sumv[400005];
data pushup(data ls,data rs){
	data res;
	for(int i=0;i<4;++i){
		res.x[i]=max(ls.x[i],rs.x[i]);
		for(int j=0;j<2;++j){
			if(ls.x[ss[i][j][0]]>-INF && rs.x[ss[i][j][1]]>-INF){
				res.x[i]=max(res.x[i],ls.x[ss[i][j][0]]+rs.x[ss[i][j][1]]);
			}
		}
	}
	return res;
}
void buildtree(int rt,int l,int r){
	if(l==r){
		ll t;
		if(l&1){
			scanf("%lld",&t);
			sumv[rt]=data(t,-INF,-INF,-INF);
		}
		else{
			scanf("%lld",&t);
			sumv[rt]=data(-INF,t,-INF,-INF);
		}
		return;
	}
	int m=(l+r>>1);
	buildtree(rt<<1,l,m);
	buildtree(rt<<1|1,m+1,r);
	sumv[rt]=pushup(sumv[rt<<1],sumv[rt<<1|1]);
}
void update(int p,ll v,int rt,int l,int r){
	if(l==r){
		if(l&1){
			sumv[rt]=data(v,-INF,-INF,-INF);
		}
		else{
			sumv[rt]=data(-INF,v,-INF,-INF);
		}
		return;
	}
	int m=(l+r>>1);
	if(p<=m){
		update(p,v,rt<<1,l,m);
	}
	else{
		update(p,v,rt<<1|1,m+1,r);
	}
	sumv[rt]=pushup(sumv[rt<<1],sumv[rt<<1|1]);
}
data query(int ql,int qr,int rt,int l,int r){
	if(ql<=l && r<=qr){
		return sumv[rt];
	}
	int m=(l+r>>1);
	data res;
	if(ql<=m && m<qr){
		res=pushup(query(ql,qr,rt<<1,l,m),query(ql,qr,rt<<1|1,m+1,r));
	}
	else if(ql<=m){
		res=query(ql,qr,rt<<1,l,m);
	}
	else{
		res=query(ql,qr,rt<<1|1,m+1,r);
	}
	return res;
}
int main(){
//	freopen("j.in","r",stdin);
	ss[0][0][0]=0; ss[0][0][1]=3; ss[0][1][0]=2; ss[0][1][1]=0;
	ss[1][0][0]=1; ss[1][0][1]=2; ss[1][1][0]=3; ss[1][1][1]=1;
	ss[2][0][0]=0; ss[2][0][1]=1; ss[2][1][0]=2; ss[2][1][1]=2;
	ss[3][0][0]=1; ss[3][0][1]=0; ss[3][1][0]=3; ss[3][1][1]=3;
	scanf("%d%d",&n,&m);
	buildtree(1,1,n);
	int op,x,y;
	for(int i=1;i<=m;++i){
		scanf("%d%d%d",&op,&x,&y);
		if(op!=1){
			printf("%lld
",query(x,y,1,1,n).maxx());
		}
		else{
			update(x,y,1,1,n);
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/autsky-jadek/p/7611613.html