传送门:【SPOJ】1557 Can you answer these queries II
题目分析:区间最大连续子段和,且子段内的相同数只计算一次。
每个数只算一次迫使我们使用离线算法:将询问离线,按照右端点排好序,然后从左到右插入每个数,每个数记录之前出现的位置,每次插入都在之前位置+1到当前位置,目的是确保每个数只计算一次。然后遇到右端点就进行一次查询。
我们用区间更新的方法,使得每个节点保存的是一段区间的值而不是一个变量。
每次更新区间【pre[ num[ i ] ] + 1, i】,pre[ num[ i ] ]为上一次num[ i ]出现的位置,区间内所有节点值+num[ i ]。
按照从左到右的顺序更新过去,每个叶子节点所在的位置L保存的是【L,R】内的元素和(R为更新到的位置)。
然后除了保存【L,R】内的元素和,我们还要保存以L为起点的最大子段和。
设置两个lazy标记,add为每次必须加标记,maxadd为前一种所有的标记里面取的最大值。
设置两个sum,now为从【L,R】内的元素和,old为前一种sum中的最大值。
pushdown的时候需要多多注意,注意一下更新的逻辑顺序就好。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
typedef long long LL ;
#define travel( e , H , u ) for ( Edge* e = H[u] ; e ; e = e -> next )
#define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define FOR( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define clr( a , x ) memset ( a , x , sizeof a )
#define cpy( a , x ) memcpy ( a , x , sizeof a )
#define ls ( o << 1 )
#define rs ( o << 1 | 1 )
#define lson ls , l , m
#define rson rs , m + 1 , r
#define rt o , l , r
#define root 1 , 1 , n
#define mid ( ( l + r ) >> 1 )
const int MAXN = 100005 ;
const int MAXE = 100005 ;
struct Edge {
int L , idx ;
Edge* next ;
} E[MAXE] , *H[MAXN] , *edge ;
int maxadd[MAXN << 2] ;
int old[MAXN << 2] ;
int now[MAXN << 2] ;
int add[MAXN << 2] ;
int pre[MAXN << 2] ;
int num[MAXN] ;
int ans[MAXN] ;
int n , q ;
void clear () {
edge = E ;
clr ( H , 0 ) ;
clr ( add , 0 ) ;
clr ( old , 0 ) ;
clr ( now , 0 ) ;
clr ( pre , 0 ) ;
clr ( maxadd , 0 ) ;
}
void addedge ( int R , int L , int idx ) {
edge -> L = L ;
edge -> idx = idx ;
edge -> next = H[R] ;
H[R] = edge ++ ;
}
void pushup ( int o ) {
old[o] = max ( old[ls] , old[rs] ) ;
now[o] = max ( now[ls] , now[rs] ) ;
}
void pushdown ( int o ) {
if ( add[o] || maxadd[o] ) {
maxadd[ls] = max ( add[ls] + maxadd[o] , maxadd[ls] ) ;
maxadd[rs] = max ( add[rs] + maxadd[o] , maxadd[rs] ) ;
old[ls] = max ( old[ls] , now[ls] + maxadd[o] ) ;
old[rs] = max ( old[rs] , now[rs] + maxadd[o] ) ;
add[ls] += add[o] ;
add[rs] += add[o] ;
now[ls] += add[o] ;
now[rs] += add[o] ;
add[o] = maxadd[o] = 0 ;
}
}
void update ( int L , int R , int v , int o , int l , int r ) {
if ( L <= l && r <= R ) {
now[o] += v ;
add[o] += v ;
maxadd[o] = max ( maxadd[o] , add[o] ) ;
old[o] = max ( now[o] , old[o] ) ;
return ;
}
int m = mid ;
pushdown ( o ) ;
if ( L <= m ) update ( L , R , v , lson ) ;
if ( m < R ) update ( L , R , v , rson ) ;
pushup ( o ) ;
}
int query ( int L , int R , int o , int l , int r ) {
if ( L <= l && r <= R ) return old[o] ;
int m = mid , res = 0 ;
pushdown ( o ) ;
if ( R <= m ) return query ( L , R , lson ) ;
if ( m < L ) return query ( L , R , rson ) ;
return max ( query ( L , R , lson ) , query ( L , R , rson ) ) ;
}
void solve () {
int l , r ;
clear () ;
FOR ( i , 1 , n ) scanf ( "%d" , &num[i] ) ;
scanf ( "%d" , &q ) ;
rep ( i , 0 , q ) {
scanf ( "%d%d" , &l , &r ) ;
addedge ( r , l , i ) ;
}
FOR ( R , 1 , n ) {
int x = num[R] + 100000 ;
update ( pre[x] + 1 , R , num[R] , root ) ;
pre[x] = R ;
travel ( e , H , R ) ans[e -> idx] = query ( e -> L , R , root ) ;
}
rep ( i , 0 , q ) printf ( "%d\n" , ans[i] ) ;
}
int main () {
while ( ~scanf ( "%d" , &n ) ) solve () ;
return 0 ;
}