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;
    }
  • 相关阅读:
    linux命令练习
    Centos修改用户密码
    Git使用
    使用SecureCRT连接虚拟机中Linux系统 和 虚拟机网络配置
    CentOS里Tomcat端口开放
    Linux下安装Tomcat
    laravel 中将DB::select 得到的内容转为数组
    nginx 转发 由于php语法错误 导致的 50x
    windows 下后台启动 redis
    sublime 非常好用的注释工具
  • 原文地址:https://www.cnblogs.com/autsky-jadek/p/7611613.html
Copyright © 2011-2022 走看看