SPOJ GSS3 单点修改+区间最大子段和

Posted Allorkiya

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SPOJ GSS3 单点修改+区间最大子段和相关的知识,希望对你有一定的参考价值。

题目大意

给定一个序列,需要支持单修和区间最大子段和,\\(n \\leq 50000\\)

思路

一个序列的最大字段和可能出现在左半侧最大子段和,右半侧最大子段和和跨越两边的最大子段和。

维护四个标记:mxsum,mxpre,mxsuf,sum,线段树操作即可。

有一个细节,查询的时候不能直接用左右孩子的最大后缀/前缀,因为查询的区间可能小于最大子段和出现的区间。

两种解决办法:

  • 记录最大子段和出现的位置,维护的时候判断边界
  • 将尽可能多的信息传递上来,用于计算。

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 5e4 + 10;
struct node 
	int l,r;
	int mxsum;
	int mxsuf;
	int mxpre;
	int sum;
;

int a[N];
struct segment_tree 
	node t[N << 2];

	void update(int rt) 
		int ch = rt << 1;
		t[rt].sum =  t[ch].sum + t[ch + 1].sum;
		t[rt].mxsum = max(max(t[ch].mxsum,t[ch + 1].mxsum),t[ch].mxsuf + t[ch + 1].mxpre);
		t[rt].mxpre = max(t[ch].mxpre,t[ch].sum + t[ch + 1].mxpre);
		t[rt].mxsuf = max(t[ch + 1].mxsuf,t[ch + 1].sum + t[ch].mxsuf);
	

	void build(int l,int r,int rt) 
		t[rt].l = l;
		t[rt].r = r;
		if(l == r) 
			t[rt].sum = t[rt].mxsuf = t[rt].mxpre = t[rt].mxsum = a[l];
			return;
		
		int mid = (l + r) >> 1;
		int ch = rt << 1;
		build(l,mid,ch);
		build(mid + 1,r,ch + 1);
		update(rt);
	

	void modify(int rt,int pos,int v) 
		if(t[rt].l == t[rt].r) 
			t[rt].sum = v;
			t[rt].mxsum = v;
			t[rt].mxpre = v;
			t[rt].mxsuf = v;
			return;
		
		int mid = (t[rt].l + t[rt].r) >> 1;
		int ch = rt << 1;
		if(pos <= mid) 
			modify(ch,pos,v);
		
		else 
			modify(ch + 1,pos,v);
		
		update(rt);
	

	node query (int l,int r,int rt) 
		if(l == t[rt].l and r == t[rt].r) 
			return t[rt];
		
		int mid = (t[rt].l + t[rt].r) >> 1;
		int ch = rt << 1;
		if(r <= mid) 
			return query(l,r,ch);
		
		else if(l > mid) 
			return query(l,r,ch + 1);
		else 
			node ret1 = query(l,mid,ch);
			node ret2 = query(mid + 1,r,ch + 1);
			node res;
			res.sum = ret1.sum + ret2.sum;
			res.mxsum = max(max(ret1.mxsum,ret2.mxsum),ret1.mxsuf + ret2.mxpre);
			res.mxpre = max(ret1.mxpre,ret1.sum + ret2.mxpre);
			res.mxsuf = max(ret2.mxsuf,ret2.sum + ret1.mxsuf);
			return res;
		
	
 ST;

int n,q;

int main () 
	cin >> n;
	for(int i = 1;i <= n; i ++) 
		cin >> a[i];
	
	ST.build(1,n,1);
	cin >> q;
	while(q --) 
		int op,l,r;
		cin >> op >> l >> r;
		if(op == 0) 
			ST.modify(1,l,r);
		
		else 
			cout << ST.query(l,r,1).mxsum << endl;
		
	
	return 0;

以上是关于SPOJ GSS3 单点修改+区间最大子段和的主要内容,如果未能解决你的问题,请参考以下文章

SPOJ GSS3 线段树系列1

SP1716 GSS3 - Can you answer these queries III

$SP1716$ $GSS3$ $-$ $Can$ $you$ $answer$ $these$ $queries$ $III$

SPOJ GSS3 (动态dp)

SP1716 GSS3 - Can you answer these queries III - 动态dp,线段树

线段树 信息维护 单点修改你能回答这些问题吗