题意:给你一个序列,支持两种操作:单点修改;询问一个区间中所有相邻位置下标奇偶性均不同的子序列中,和最大的是多少。
线段树每个结点维护四个值:
以奇数下标开始到奇数下标结束的最大子序列和;
以偶数下标开始到偶数下标结束的最大子序列和;
以奇数下标开始到偶数下标结束的最大子序列和;
以偶数下标开始到奇数下标结束的最大子序列和。
合并的时候先在左右两区间中取较大者,然后奇-偶的答案能通过奇-奇+偶-偶、奇-偶+奇-偶得到;奇-奇的答案能通过奇-奇+偶-奇、奇-偶+奇-奇得到……这样讨论一下。
#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; }