[Vijos 1083] 小白逛公园 · 线段树

总体为带单点修改的查询区间最大连续子段和。

对每个区间维护四个值: left_max , right_max , sum , ans .分别是区间的最大前缀和,最大后缀和,区间总和,以及最大连续子段和(也就是要求的值)。

对于当前区间father[l,r] ,下属的两个区间分别为son1,son2,father的left_max等于 max (son1.left_max , son1.sum + son2.left_max),即左孩子的最大前缀和 或 左孩子的区间总和加上右孩子的最大前缀和(见下图)

对于最大后缀和也是一个意思,


那么father.ans 怎么合并呢:son1.right_max + son2.left_max 连起来构成了一个连续的子段,然后再和son1.ans、son2.ans比较取最大值。

代码的时候对于更新合并操作可以重载运算符来简化程序。

#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;

const int N = 500005;
int n,m,a[N],p,x,y;
struct arr {
	int x,l,r,s;
}t[N * 4];

arr operator *( arr a , arr b ) {
	arr c ;
	c.s = a.s + b.s ;
	c.x = max( max( a.x , b.x ) , a.r + b.l ) ;
	c.l = max( a.l , a.s + b.l ) ;
	c.r = max( b.r , b.s + a.r ) ;
	return c ;
}

inline void build( int l , int r , int p ) {
	if ( l == r ) {
		t[ p ].s = t[ p ].l = t[ p ].r = t[ p ].x = a[ l ] ;
		return ;
	}
	int mid = ( l + r ) >> 1 ; 
	build( l , mid , p + p + 1 ) ;
	build( mid + 1 , r , p + p + 2 ) ;
	t[ p ] = t[ p + p + 1 ] * t[ p + p + 2 ] ;
	return ;
}

inline void edit( int l , int r , int  p ) {
	if ( l > r || l > x || r < x ) return ;
	if ( l == r ) {
		t[ p ].s = t[ p ].l = t[ p ].r = t[ p ].x = a[ l ] = y ;
		return ;
	}
	int mid = ( l + r ) >> 1 ;
	edit( l , mid , p + p + 1 ) ;
	edit( mid + 1 , r , p + p + 2) ;
	t[ p ] = t[ p + p + 1 ] * t[ p + p + 2 ] ;
	return ;
}

inline arr query( int l , int r , int  p ) {
	if ( l > r || l > y || r < x ) return (arr){ -0x7fffff , -0x7fffff , -0x7fffff , -0x7fffff } ;
	if ( x <= l && r <= y ) return t[ p ];
	int mid = ( l + r ) >> 1;
	arr ret,left,right;
	left = query( l , mid , p + p + 1 ) ; 
	right = query( mid + 1, r , p + p + 2) ;
	ret = left * right ;
	return ret ;
}

int get() {
	int p = 0 , t = 1 ; char x = getchar() ;
	while ( x < '0' || x > '9') {
		if ( x == '-' ) t = -t ;
		x = getchar() ;
	}
	while ( x >= '0' && x <= '9' ) p = p * 10 + x - '0' , x = getchar() ;
	return p * t ;
}

int main() {
	#ifndef ONLINE_JUDGE
	freopen("1083.in" , "r" , stdin) ;
	freopen("1083.out" , "w" , stdout) ;
	#endif
	n = get() ; m = get() ; 
	for (int i = 1 ; i <= n ; i++) a[ i ] = get() ;
	build( 1 , n , 0 );
	while ( m-- ) {
		p = get() ; x = get() ; y = get() ;
		if ( x > y ) swap( x , y ) ;
		if ( p == 1 ) {
			arr ans = query( 1 , n , 0 ) ;
			printf("%d\n", ans.x) ; 
		}
		else edit( 1 , n , 0 ) ;
	}
	return 0 ;
}
其实我也不知道怎么会TLE  明明随机数据只跑了400ms orz

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值