您的位置:首页 > 产品设计 > UI/UE

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

2013-01-03 20:07 441 查看
原题地址: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<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<cmath>
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<<ans[i]<<endl;
}
}


参考题解 : http://hi.baidu.com/lemon_workshop/item/2bcf00cf47e35a2da1b50a43
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: