SPOJ 1557. Can you answer these queries II (很强的线段树)

原题地址:https://www.spoj.com/problems/GSS2/

题意:询问任意区间内,最大连续序列和(相等的值不重复计算),可以不选输出0;

这题可以说一眼看出是线段树了,可是怎么构造确实非常难. 现在假设线段树中的叶子为 s[i]. 每次更新 a[i]的时候,s[1] -s[i]区间内加上a[i];那么

s[1] = a[1] + a[2] + a[3] + ... + a[i];
s[2] = a[2] + a[3] + ... + a[i];

s[3] = a[3] + ... + a[i];

s[i] = a[i];


变形一下就是所求

ss[1] = max( a[1] + a[2]  + ... + a[k1] ) (    k1 <= i );

ss[2] = max( a[2] + a[3] + ...+ a[k2] )  (    k2 <= i );

我们可以求的是以i为右端点的询问,就是 ss[l] ....ss[r]( r == i ) 中的最大值;

到这里还有一个问题需要解决, 重复出现的值不计算??

可以这样:在更新a[i]的时候,更新区间不是1---i 而是pre[a[i]] --- i (pre[a[i]]是a[i]上一次出现的位置);这样就可以解决重复计算问题

线段树结构中:

curmax表示此区间内的最优值

prelazy即将下传的最大值;

lazy为即将下传的总值;

sum表示的区间内 max( s[] );

#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define M 100007

struct Tree
{
	int l, r;
	long long curmax, prelazy, lazy, sum;
}tree[M*4];
int a[M], n, m, pre[M*2+10];
struct Node
{
	int l, r, id;
}nde[M];
long long ans[M];

bool cmp( Node a, Node b )
{
	return a.r < b.r;
}
void build( int l, int r, int p )
{
	tree[p].l = l; tree[p].r = r;
	tree[p].curmax = tree[p].prelazy = 0;
	tree[p].sum = tree[p].lazy = 0;
	if( l >= r ) return;
	int mid = (l+r)>>1;
	build( l, mid, p<<1 );
	build( mid+1, r, p<<1|1 );
}

void pushDown( int p )
{
	int ls = p<<1, rs = ls|1;
	if( tree[p].lazy || tree[p].prelazy ){
		tree[ls].prelazy = max( tree[ls].prelazy, tree[ls].lazy + tree[p].prelazy );
		tree[ls].curmax = max( tree[ls].curmax, tree[ls].sum + tree[p].prelazy );
		tree[ls].lazy += tree[p].lazy; tree[ls].sum += tree[p].lazy;

		tree[rs].prelazy = max( tree[rs].prelazy, tree[rs].lazy + tree[p].prelazy );
		tree[rs].curmax = max( tree[rs].curmax, tree[rs].sum + tree[p].prelazy );
		tree[rs].lazy += tree[p].lazy; tree[rs].sum += tree[p].lazy;

		tree[p].lazy = 0; tree[p].prelazy = 0;
	}
}

void pushUp( int p )
{
	tree[p].sum = max( tree[p<<1].sum, tree[p<<1|1].sum );
	tree[p].curmax = max( tree[p<<1].curmax, tree[p<<1|1].curmax );
}
void insert( int l, int r, int p, long long x )
{
	if( l <= tree[p].l && r >= tree[p].r ){
		tree[p].sum += x;
		tree[p].lazy += x;
		tree[p].prelazy = max( tree[p].prelazy, tree[p].lazy );
		tree[p].curmax = max( tree[p].curmax, tree[p].sum );
		return;
	}
	if( l > tree[p].r || r < tree[p].l ) return;
	pushDown( p );
	insert( l, r, p<<1, x );
	insert( l, r, p<<1|1, x );
	pushUp( p );
}

long long query( int l, int r, int p )
{
	if( l <= tree[p].l && r >= tree[p].r ){
		return tree[p].curmax;
	}
	if( l > tree[p].r || r < tree[p].l ) return 0;
	pushDown( p );
	return max( query(l, r, p<<1), query(l, r, p<<1|1) );
	//pushUp( p );
}
int main()
{
	while( scanf( "%d", &n ) == 1 ){
		for( int i = 1; i <= n; i++ )
			scanf( "%d", a+i );
		scanf( "%d", &m );
		build( 1, n, 1 );
		for( int i = 0; i < m; i++ ){
			scanf( "%d%d", &nde[i].l, &nde[i].r );
			nde[i].id = i;
		}
		sort( nde, nde + m, cmp );
		memset( pre, 0, sizeof(pre) );
		int j = 0;
		for( int i = 1; i <= n; i++ ){
			insert( pre[a[i]+M]+1, i, 1, a[i] );
			pre[a[i]+M] = i;
			while( j < m && nde[j].r == i ){
				ans[nde[j].id] = query( nde[j].l, nde[j].r, 1 );
				j++;
			}
		}

		for( int i = 0; i < m; i++ )
			cout<

参考题解 : http://hi.baidu.com/lemon_workshop/item/2bcf00cf47e35a2da1b50a43 

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