传送门:【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 ; }