小白逛公园 线段树维护 最大前缀和,后缀和

luogu -区间求最大和
线段树维护 最大前缀和,后缀和

  • P4513 小白逛公园
    提交 2.71k
    通过 874
    时间限制 1.00s
    内存限制 128.00MB
    题目提供者 huhao
    难度
    省选/NOI-
    历史分数 100
    提交记录 查看题解
    标签
    相关讨论
    进入讨论版
    推荐题目
    展开
    题目背景

小新经常陪小白去公园玩,也就是所谓的遛狗啦…
题目描述

在小新家附近有一条“公园路”,路的一边从南到北依次排着nnn个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了。

一开始,小白就根据公园的风景给每个公园打了分-.-。小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只可以选择第aaa个和第bbb个公园之间(包括aaa、bbb两个公园)选择连续的一些公园玩。小白当然希望选出的公园的分数总和尽量高咯。同时,由于一些公园的景观会有所改变,所以,小白的打分也可能会有一些变化。

那么,就请你来帮小白选择公园吧。
输入格式

第一行,两个整数NNN和MMM,分别表示表示公园的数量和操作(遛狗或者改变打分)总数。
接下来NNN行,每行一个整数,依次给出小白 开始时对公园的打分。
接下来MMM行,每行三个整数。第一个整数KKK,111或222。

K=1K=1K=1表示,小新要带小白出去玩,接下来的两个整数aaa和bbb给出了选择公园的范围(1≤a,b≤N1≤a,b≤N1≤a,b≤N)。测试数据可能会出现a>ba>ba>b的情况,需要进行交换;
K=2K=2K=2表示,小白改变了对某个公园的打分,接下来的两个整数ppp和sss,表示小白对第ppp个公园的打分变成了sss(1≤p≤N1≤p≤N1≤p≤N)。
其中,1≤N≤5000001≤N≤500 0001≤N≤500000,1≤M≤1000001≤M≤100 0001≤M≤100000,所有打分都是绝对值不超过100010001000的整数。

输出格式

小白每出去玩一次,都对应输出一行,只包含一个整数,表示小白可以选出的公园得分和的最大值。
输入输出样例
输入 #1

5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 2 3

输出 #1

2
-1

#include
using namespace std;
const int N=500010;
struct Tree
{
     
	int pre,s,suf,v;
}tree[4*N];
int a[N];
Tree pushup(Tree &l,Tree &r )
{
     
	Tree rt;
	rt.pre=max(l.pre,l.v+r.pre);//最大前缀和 
	rt.suf=max(r.suf,r.v+l.suf);//最大后缀和 
	rt.v=l.v+r.v;//当前区间的和 
	rt.s=max(max(l.s,r.s),l.suf+r.pre);//最大子段和 
	return  rt; 
 } 
 void build(int l,int r,int x)
 {
     
 	if(l==r)
 	{
     
 		tree[x].pre=tree[x].suf=tree[x].s=tree[x].v=a[l];
 		return ;
	}
	int mid=(l+r)>>1;
	build(l,mid,x<<1);
	build(mid+1,r,x<<1|1);
	tree[x]=pushup(tree[x<<1],tree[x<<1|1]);
 }
 void update(int pos,int c,int l,int r,int x)
 {
     
 	if(l==r)
 	{
     
 		tree[x].pre=tree[x].suf=tree[x].s=tree[x].v=c;
 		return ;
	 }
	 int mid=(l+r)>>1;
	 if(pos<=mid) update(pos,c,l,mid,x<<1);
	 if(pos>mid) update(pos,c,mid+1,r,x<<1|1);
	 tree[x]=pushup(tree[x<<1],tree[x<<1|1]); 
 }
 Tree query(int L,int R,int l,int r,int x)
 {
     
 	if(L<=l&&R>=r)
 	{
     
 		return tree[x]; 
	} 
	int mid=(l+r)>>1;
	Tree ret,lret,rret;
	int f1=0,f2=0;
	if(L<=mid)
	{
     
		lret=query(L,R,l,mid,x<<1);
		f1=1;
	}
	if(R>mid) 
	{
     
		rret=query(L,R,mid+1,r,x<<1|1);
		f2=1;
	}
	if(f1&&f2)
	{
     
		ret=pushup(lret,rret);
	}else if(f1)
	{
     
		ret=lret;
	} else if(f2)
	{
     
		ret=rret;
	}
	return  ret;
 }
 int main()
 {
     
 	int n,m;
 	scanf("%d%d",&n,&m);
 	for(int i=1;i<=n;i++)
 	{
     
 		scanf("%d",&a[i]);
	 }
	 build(1,n,1);
	 for(int i=1;i<=m;i++)
	 {
     
	 	int op;
	 	scanf("%d",&op);
	 	if(op==1)
	 	{
     
	 		int l,r;
	 		scanf("%d%d",&l,&r);
	 		if(l>r) swap(l,r);
	 		Tree ans=query(l,r,1,n,1);
	 		printf("%d\n",ans.s);
		 }else 
		 {
     
		 	int p,s;
		 	scanf("%d%d",&p,&s);
		 	update(p,s,1,n,1);
		 	
		 }
		 
	 }
 }

你可能感兴趣的:(~线段树)