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

【线段树】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;
}