UVALive - 3938 "Ray, Pass me the dishes!" 线段树单点更新

需要注意的是  此题为动态查询,因为有多个询问,且范围给定

输出的答案   应保证x小,在x小的情况下y小,这只要在判断时调整判断顺序即可,

详见  紫书  p201  讲解很清晰,

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <cmath>
#include <set>
#include <queue>
using namespace std;
typedef long long ll;
const int INF=1e9+10;
const double EPS = 1e-10;  
const ll mod=1e9+7;
typedef pair<int,int> P;
 
const int N=5000001;

int n,m;

struct Node{
	ll suf,sub,pre,sum;
	int l,r,prer,sufl;
}node[4*N];

void pushup(Node &rt,Node a,Node b){
	ll mx;
	mx=a.sub;
	rt.sub=mx;
	rt.l=a.l;
	rt.r=a.r;
	if(mx<a.suf+b.pre){
		mx=1LL*a.suf+b.pre;
		rt.sub=mx;
		rt.l=a.sufl;
		rt.r=b.prer;
	}
	if(mx<b.sub){
		mx=b.sub;
		rt.sub=mx;
		rt.l=b.l;
		rt.r=b.r;
	}
	mx=a.pre;
	rt.pre=mx;
	rt.prer=a.prer;
	if(mx<a.sum+b.pre){
		rt.pre=1LL*a.sum+b.pre;
		rt.prer=b.prer;
	}
	mx=1LL*b.sum+a.suf;
	rt.suf=mx;
	rt.sufl=a.sufl;
	if(mx<b.suf){
		rt.suf=b.suf;
		rt.sufl=b.sufl;
	}
	rt.sum=1LL*a.sum+b.sum;
}

void build(int l,int r,int rt){
	if(l==r){
		int x;
		scanf("%d",&x);
		node[rt].sum=node[rt].pre=node[rt].suf=node[rt].sub=1LL*x;
		node[rt].l=node[rt].r=node[rt].prer=node[rt].sufl=l;
		return;
	}
	int mid=(l+r)/2;
	build(l,mid,rt*2);
	build(mid+1,r,rt*2+1);
	pushup(node[rt],node[rt*2],node[rt*2+1]);
}

Node query(int L,int R,int l,int r,int rt){
	if(L<=l&&r<=R){
		return node[rt];
	}
	Node tmp,a,b;
	int mid=(l+r)/2;
	if(L<=mid){
		a=query(L,R,l,mid,rt*2);
	}
	if(R>mid){
		b=query(L,R,mid+1,r,rt*2+1);
	}
	if(L<=mid&&R>mid){
		pushup(tmp,a,b);
		return tmp;
	}
	else if(L<=mid){
		return a;
	}
	else{
		return b;
	}
}
int main(){
	//freopen("out.txt","w",stdout);
	//ios_base::sync_with_stdio(0);
	int case1=1;
	while(scanf("%d %d",&n,&m)!=EOF){
		build(1,n,1);
		printf("Case %d:\n",case1++);
		while(m--){
			int l,r;
			scanf("%d %d",&l,&r);
			Node tmp=query(l,r,1,n,1);
			printf("%d %d\n",tmp.l,tmp.r );
		}
	}	  
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值