[BZOJ4540]-[Hnoi2016]序列-線段樹維護資訊
阿新 • • 發佈:2018-11-11
說在前面
馬上就要NOI了啊…
題目
BZOJ4540傳送門
看題可戳傳送門
解法
這是一道,「不帶修改、區間詢問」類問題。很容易想到莫隊
對於這一類題,也可以使用線段樹來解決。離線所有詢問,從左到右依次加入資訊,對於已經加入的位置
,維護
的資訊。在相應的位置處理區間詢問
然後這道題,題解可以看這位的,傳送門,思路很清晰
這道題使用類似矩陣乘法的東西去維護,就是因為其標記只有「加法」和「乘法」,而這個東西滿足結合律(動態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() ;
}