1. 程式人生 > >[BZOJ4540]-[Hnoi2016]序列-線段樹維護資訊

[BZOJ4540]-[Hnoi2016]序列-線段樹維護資訊

說在前面

馬上就要NOI了啊…


題目

BZOJ4540傳送門
看題可戳傳送門


解法

這是一道,「不帶修改、區間詢問」類問題。很容易想到莫隊
對於這一類題,也可以使用線段樹來解決。離線所有詢問,從左到右依次加入資訊,對於已經加入的位置 i ,維護

i n o w 的資訊。在相應的位置處理區間詢問

然後這道題,題解可以看這位的,傳送門,思路很清晰
這道題使用類似矩陣乘法的東西去維護,就是因為其標記只有「加法」和「乘法」,而這個東西滿足結合律(動態dp也是類似思想吧

感覺推廣性挺強的,mark一下


下面是程式碼

    Problem: 4540
    User: Izumihanako     Language: C++     Result: Accepted     Time:3256 ms     Memory:16060 kb ****************************************************************/   #include <cstdio> #include <cstring>
#include <algorithm> using namespace std ;   long long ans[100005] ; int N , Q , a[100005] ; struct Queries{     int L , R , id ;     bool operator < ( const Queries &A ) const {         return R < A.R ;     } } q[100005] ;   struct Node{     Node *ch[2] ;     long long len , val , sum ;     long long a , b , c , d ;     void muls( long long A , long long B , long long C , long long D ){         long long ta = a * A ;         long long tb = b + a * B ;         long long tc = c * A + C ;         long long td = d + c * B + D ;         a = ta , b = tb , c = tc , d = td ;           sum = sum + D * len + B * val ;         val = C * len + A * val ;     }     void pushdown(){         if( a == 1 && !b && !c && !d ) return ;         ch[0]->muls( a , b , c , d ) ;         ch[1]->muls( a , b , c , d ) ;         a = 1 , b = c = d = 0 ;     }     void update(){         val = ch[0]->val + ch[1]->val ;         sum = ch[0]->sum + ch[1]->sum ;     } } *root , w[200005] , *tw = w ;   Node *build( int lf , int rg ){     Node *nd = ++tw ;     nd->a = 1 , nd->len = ( rg - lf + 1 ) ;     if( lf != rg ){         int mid = ( lf + rg ) >> 1 ;         nd->ch[0] = build( lf , mid ) ;         nd->ch[1] = build( mid+1,rg ) ;     } return nd ; }   void preWork(){     root = build( 1 , N ) ;     sort( q + 1 , q + Q + 1 ) ; }   int L , R ; long long A , B , C , D ; void Modify( Node *nd , int lf , int rg ){     if( L <= lf && rg <= R ){ nd->muls( A , B , C , D ) ; return ; }     int mid = ( lf + rg ) >> 1 ;     nd->pushdown() ;     if( L <= mid ) Modify( nd->ch[0] , lf , mid ) ;     if( R >  mid ) Modify( nd->ch[1] , mid+1,rg ) ;     nd->update() ; }   long long Query( Node *nd , int lf , int rg ){     if( L <= lf && rg <= R ) return nd->sum ;     int mid = ( lf + rg ) >> 1 ; long long rt = 0 ;     nd->pushdown() ;     if( L <= mid ) rt += Query( nd->ch[0] , lf , mid ) ;     if( R >  mid ) rt += Query( nd->ch[1] , mid+1,rg ) ;     return rt ; }   int sta[100005] , top ; void solve(){     for( int i = 1 , pt = 1 ; i <= N && pt <= Q ; i ++ ){         while( top && a[ sta[top] ] >= a[i] ) top -- ;         L = sta[top] + 1 , R = i , A = B = D = 0 , C = a[i] , Modify( root , 1 , N ) ;         L = 1 , R = i , A = B = 1 , C = D = 0 , Modify( root , 1 , N ) ;         sta[++top] = i ;                   R = i ;         while( pt <= Q && q[pt].R == i ){             L = q[pt].L , ans[ q[pt].id ] = Query( root , 1 , N ) ;             pt ++ ;         }     } for( int i = 1 ; i <= Q ; i ++ )         printf( "%lld\n" , ans[i] ) ; }   int main(){     scanf( "%d%d" , &N , &Q ) ;     for( int i = 1 ; i <= N ; i ++ )         scanf( "%d" , &a[i] ) ;     for( int i = 1 ; i <= Q ; i ++ )         scanf( "%d%d" , &q[i].L , &q[i].R ) , q[i].id = i ;     preWork() ; solve() ; }