zoukankan      html  css  js  c++  java
  • 【线段树】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;
    }
  • 相关阅读:
    codeforces C. Cows and Sequence 解题报告
    codeforces A. Point on Spiral 解题报告
    codeforces C. New Year Ratings Change 解题报告
    codeforces A. Fox and Box Accumulation 解题报告
    codeforces B. Multitasking 解题报告
    git命令使用
    shell简单使用
    知识束缚
    php 调用系统命令
    数据传输方式(前端与后台 ,后台与后台)
  • 原文地址:https://www.cnblogs.com/autsky-jadek/p/7611613.html
Copyright © 2011-2022 走看看