UVa Ray, Pass me the dishes! (线段树)

白书上的线段树例题。

题意 : 给你一个数组,然后有m次询问,每次询问一个区间,返回在这个区间里面最大的连续和的起始和结束位置、

思路 :每个节点记录前缀max_pre和和后缀和max_suf来维护它的最大连续和max_sub。(其实思路白书上讲了,就是代码实现而已)需要注意的是这道题目的max_pre,max_suf,max_sub都是需要用long long 来保存的。


#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long lld;

const int MAXN = 500005;
const int INF = 100000007;

struct MAX
{
	lld Max;
	int l,r;
};

struct node
{
	MAX sub, pre, suf;
	lld sum;
}ans[MAXN<<2];
int n,m;

void init(node &a,int v)
{
	MAX  e;
	e.Max = v;
	e.l = -INF; e.r = INF;
	a.pre = a.sub = a.suf = e;
	a.sum = v;
}

void push_up(node &mid,node &ll,node &rr)
{
	mid.sum = ll.sum + rr.sum;
	if (ll.pre.Max >= rr.pre.Max + ll.sum)
	{
		mid.pre = ll.pre;
	}
	else
	{
		mid.pre.Max = rr.pre.Max + ll.sum;
		mid.pre.l = ll.pre.l;
		mid.pre.r = rr.pre.r;
	}
	if (rr.suf.Max > rr.sum + ll.suf.Max)
	{
		mid.suf = rr.suf;
	}
	else
	{
		mid.suf.Max = rr.sum + ll.suf.Max;
		mid.suf.l = ll.suf.l;
		mid.suf.r = rr.suf.r;
	}
	lld temp = ll.suf.Max + rr.pre.Max;
	lld t1 = ll.sub.Max, t2 = rr.sub.Max;
	
	if (t1 >= temp && t1 >= t2)
	{
		mid.sub = ll.sub;
	}
	else if (temp >= t1 && temp >= t2)
	{
		mid.sub.Max = temp;
		mid.sub.l = ll.suf.l;
		mid.sub.r = rr.pre.r;
	}
	else
	{
		mid.sub = rr.sub;
	}
}

void update(int rt,int L,int R,int p,int v)
{
	if (L == R)
	{
		ans[rt].sub.Max = ans[rt].pre.Max = ans[rt].suf.Max = v;
		ans[rt].sum = v;
		ans[rt].sub.l = ans[rt].sub.r = p;
		ans[rt].pre.l = ans[rt].pre.r = p;
		ans[rt].suf.l = ans[rt].suf.r = p;
	}
	else
	{
		int M = (L + R) >> 1;
		if (p <= M)update(rt<<1,L,M,p,v);
		else update(rt<<1|1,M+1,R,p,v);
		if (ans[rt<<1].sum != -INF)
		{
			if (ans[rt<<1|1].sum != -INF)
				push_up(ans[rt],ans[rt<<1],ans[rt<<1|1]);
			else ans[rt] = ans[rt<<1];
		}
		else ans[rt] = ans[rt<<1|1];
	}
}

node query(int rt,int L,int R,int l,int r)
{
	int M = (L + R) >> 1;
	node tl,tr,res;
	init(tl,-INF); init(tr,-INF);
	if (L >= l && R <= r)return ans[rt];
	if (M >= l)
	{
		tl = query(rt<<1,L,M,l,r);
	}
	if (r > M)
	{
		tr = query(rt<<1|1,M+1,R,l,r);
	}
	if (tl.sum != -INF)
	{
		if (tr.sum != -INF)
		{
			push_up(res,tl,tr);
			return res;
		}
		else return tl;
	}
	else return tr;
}

int main()
{
	int cas = 1 , i;
	while (scanf("%d%d",&n,&m) == 2)
	{
		for (i = 1;i <= 4*n;i++)init(ans[i],-INF);
		for (i = 1;i <= n;i++)
		{
			int a;
			scanf("%d",&a);
			update(1,1,n,i,a);
		}
		printf("Case %d:\n",cas++);
		while (m--)
		{
			int ql,qr;
			scanf("%d%d",&ql,&qr);
			node  res = query(1,1,n,ql,qr);
			printf("%d %d\n",res.sub.l,res.sub.r);
		}
	}
	return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值