洛谷 P4513 小白逛公园

前言(本质是废话)

\(lxl\) 学习数据结构,%%%畏惧了。

话说其实蜡笔小新挺好看的。

切入正题

题目传送门

带修区间最大子段和,有一个长为 \(n\) 的序列,给定 \(m\) 次操作,分别为:

  • 将第 \(a\) 个数修改为 \(b\)

  • 查询区间 \(a\)\(b\) 之间的最大子段和(可包含 \(a\)\(b\));

很显然需要使用线段树维护区间最大子段和,那么工具选好了,现在就需要考虑如何使用了。

眼前一个巨大的问题就是如何合并一个节点左右儿子带来的贡献。

设每个区间的包含最左端点的子段最大和\(left\_sum\),另一边同理设包含最右端点的子段最大和\(right\_sum\),我们考虑分类讨论:

  • 若区间内的和最大的子段完全处于左半边,那么直接继承左儿子的答案;

  • 若和最大的子段完全属于右半边,同理直接继承答案;

  • 若该子段跨越左右两边,那么有如下柿子:最大子段和 \(=\) \(left\_sum\) \(+\) \(right\_sum\)

关于 \(left\_sum\)\(right\_sum\) 的合并柿子如下:

  • 区间的 \(left\_sum\) \(=\) \(max(\) 左区间的 \(left\_sum\) \(,\) 左区间的区间和 \(+\) 右区间的 \(left\_sum\) );

  • 区间的 \(right\_sum\) \(=\) \(max(\) 右区间的 \(right\_sum\) \(,\) 右区间的区间和 \(+\) 左区间的 \(right\_sum\) );

维护区间和 \(sum\) 就是普通线段树的操作,就等于左右区间的区间和之和。

那么剩下来的就是线段树的各种常规操作了。

\(Code\)

#include<bits/stdc++.h>
using namespace std;
int val[500005];
struct node{
	int L,R,sum,max_sum,left_sum,right_sum;
};
node tree[2000005];
void pushup(node &u,node ls,node rs){
	u.max_sum=max(max(ls.max_sum,rs.max_sum),ls.right_sum+rs.left_sum);
	u.sum=ls.sum+rs.sum;
	u.left_sum=max(ls.left_sum,ls.sum+rs.left_sum);
	u.right_sum=max(rs.right_sum,rs.sum+ls.right_sum);
	return;
}
void buildtree(int u,int l,int r){
	tree[u].L=l,tree[u].R=r;
	tree[u].sum=tree[u].max_sum=tree[u].left_sum=tree[u].right_sum=INT_MIN;
	if(l==r){
		tree[u].sum=tree[u].max_sum=tree[u].left_sum=tree[u].right_sum=val[l];
		return;
	}
	int mid=(l+r)/2;
	buildtree(2*u,l,mid),buildtree(u*2+1,mid+1,r);
	pushup(tree[u],tree[u*2],tree[u*2+1]);
	return;
}
void merge(int goal,int goalval,int u){
	if(goal==tree[u].L&&goal==tree[u].R){
		tree[u].sum=tree[u].max_sum=tree[u].left_sum=tree[u].right_sum=goalval;
		return;
	}
	int mid=(tree[u].L+tree[u].R)/2;
	if(goal<=mid) merge(goal,goalval,u*2);
	else merge(goal,goalval,u*2+1);
	pushup(tree[u],tree[u*2],tree[u*2+1]);
	return;
}
node query(int gl,int gr,int u){
	int l=tree[u].L,r=tree[u].R;
	if(gl>r||gr<l) return {0,0,INT_MIN,INT_MIN,INT_MIN,INT_MIN};
	if(l>=gl&&r<=gr) return tree[u];
	int mid=(l+r)/2;
	if(gr<=mid) return query(gl,gr,u*2);
	if(gl>mid) return query(gl,gr,u*2+1);
	node left=query(gl,gr,u*2);
	node right=query(gl,gr,u*2+1);
	node res;
	pushup(res,left,right);
	return res;
}
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&val[i]);
	buildtree(1,1,n);
	for(int i=1;i<=m;i++){
		int opt,a,b;
		scanf("%d%d%d",&opt,&a,&b);
		if(opt==1) printf("%d\n",query(min(a,b),max(a,b),1).max_sum);
		else merge(a,b,1);
	}
	return 0;
}

\(-\) ❀ 完结撒花 ❀ \(-\)

posted @ 2026-04-02 19:21  Rye-Whiskey  阅读(14)  评论(0)    收藏  举报