【ybt】【数据结构 线段树 课过 例3】小白逛公园

小白逛公园

题目链接:YbtOJ/Luogu


在这里插入图片描述

解题思路

我们用线段树维护 m a x v , m a x l , m a x r , s maxv,maxl,maxr,s maxv,maxl,maxr,s 四个值,分别代表区间最大值,包含左端点在内的最大值,包括右端点内的最大值和区间总值。

显然,对于一个节点,它的转移方程如下:

	now.s=l.s+r.s;
	now.maxl=max(l.maxl,l.s+r.maxl);
	now.maxr=max(r.maxr,r.s+l.maxr);
	now.maxv=max(l.maxv,max(l.maxr+r.maxl,r.maxv));

code

#include<iostream>
#include<cstdio>
using namespace std;

int n,m;

struct abc{
	int s;
	int maxl,maxr,maxv;
}tree[2000010];

abc add(abc a,abc b)
{
	abc c;
	c.s=a.s+b.s;
	c.maxl=max(a.maxl,a.s+b.maxl);
	c.maxr=max(b.maxr,b.s+a.maxr);
	c.maxv=max(a.maxv,max(a.maxr+b.maxl,b.maxv));
	return c;
}

void down(abc &now,abc &l,abc &r)
{
	if(l.maxr<0&&r.maxl<0)
		now.maxv=max(l.maxr,r.maxl);
	else
	{
		now.maxv=0;
		if(l.maxr>0)
			now.maxv+=l.maxr;
		if(r.maxl>0)
			now.maxv+=r.maxl;
	}
	now.maxv=max(now.maxv,l.maxv);
	now.maxv=max(now.maxv,r.maxv);
	now.maxl=max(l.maxl,l.s+r.maxl);
	now.maxr=max(r.maxr,r.s+l.maxr);
	now.s=l.s+r.s;
}

void build(int now,int x,int y)
{
	if(x==y)
	{
		scanf("%d",&tree[now].s);
		tree[now].maxl=tree[now].maxr=tree[now].maxv=tree[now].s;
		return;
	}
	int mid=(x+y)/2;
	build(now*2,x,mid);
	build(now*2+1,mid+1,y);
	down(tree[now],tree[now*2],tree[now*2+1]);
}

void change(int now,int x,int y,int p,int v)
{
	if(x==y)
	{
		tree[now].s=tree[now].maxl=tree[now].maxr=tree[now].maxv=v;
		return;
	}
	int mid=(x+y)/2;
	if(p<=mid)
		change(now*2,x,mid,p,v);
	else
		change(now*2+1,mid+1,y,p,v);
	down(tree[now],tree[now*2],tree[now*2+1]);
}

abc fd(int now,int x,int y,int l,int r)
{
	if(l<=x&&y<=r)
		return tree[now];
	int mid=(x+y)/2;
	if(r<=mid)
		return fd(now*2,x,mid,l,r);
	if(l>mid)
		return fd(now*2+1,mid+1,y,l,r);
	abc a,b;
	a=fd(now*2,x,mid,l,r);
	b=fd(now*2+1,mid+1,y,l,r);
	return add(a,b);
}

int main()
{
	cin>>n>>m;
	build(1,1,n);
	while(m--)
	{
		int k,a,b;
		scanf("%d%d%d",&k,&a,&b);
		if(k==1)
		{
			if(a>b)
				swap(a,b);
			cout<<fd(1,1,n,a,b).maxv<<endl;
		}
		else
			change(1,1,n,a,b);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值