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[] );
参考题解 : http://hi.baidu.com/lemon_workshop/item/2bcf00cf47e35a2da1b50a43
题意:询问任意区间内,最大连续序列和(相等的值不重复计算),可以不选输出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
相关文章推荐
- 【BZOJ2482】[Spoj1557] Can you answer these queries II 线段树
- SPOJ 1557 Can you answer these queries II(线段树)
- spoj 1557 Can you answer these queries II (gss2)线段树
- SPOJ 1557 Can you answer these queries II(GSS2 线段树)
- Spoj 1557 Can you answer these queries II 线段树 随意区间最大子段和 不反复数字
- spoj 1557. Can you answer these queries II(线段树)
- Spoj 1557 Can you answer these queries II 线段树 任意区间最大子段和 不重复数字
- [SPOJ1557][GSS2][线段树]Can you answer these queries II[好题]
- SPOJ 1557 Can you answer these queries II(离线处理+线段树求历史最大)
- 【SPOJ】1557 Can you answer these queries II 线段树
- SPOJ 1557. Can you answer these queries II 线段树
- SPOJ GSS2 Can you answer these queries II ——线段树
- BZOJ 2482 || SPOJ GSS2 Can you answer these queries II(线段树 离线 后缀和)
- [SPOJ GSS2] Can you answer these queries II [线段树]
- bzoj2482 [Spoj1557] Can you answer these queries II
- bzoj 2482: [Spoj GSS2] Can you answer these queries II 线段树
- BZOJ2482: [Spoj1557] Can you answer these queries II
- 【SPOJ - GSS2】Can you answer these queries II(线段树)
- 【SPOJ】1557 Can you answer these queries II
- 【线段树】spoj GSS2 Can you answer these queries II