题解
记
Prei
表示
i
前面恰好比
对于一个询问
[l,r]
考虑将
p1,p2
的贡献分开计算。对于
p1
,要满足
max(ki+1,...,kj−1)≤min(ki,kj)
,一个位置
i
将其当做较小值,那么贡献就是
时间复杂度: O(nlogn)
SRC
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std ;
#define N 200000 + 10
const int MAXN = 19 ;
typedef long long ll ;
struct Query {
int l , r ;
} Q[N] ;
struct Tree {
int Son[2] ;
int tot ;
ll Sum1 , Sum2 ;
} T[20*N] ;
int Tab[N] ;
int f[N][MAXN] ;
int a[N] , Pre[N] , Next[N] , Root[N] ;
int n , m , p1 , p2 , Cnt ;
ll tot1[N] , tot2[N] ;
ll ret1 , ret2 , ret3 ;
int Read() {
int ret = 0 ;
char ch = getchar() ;
while ( ch < '0' || ch > '9' ) ch = getchar() ;
while ( ch >= '0' && ch <= '9' ) {
ret = ret * 10 + ch - '0' ;
ch = getchar() ;
}
return ret ;
}
int Find( int l , int r ) {
int k = Tab[r-l+1] ;
return max( f[l][k] , f[r-(1<<k)+1][k] ) ;
}
int Lbinary( int l , int r , int s ) {
int ret = s ;
while ( l <= r ) {
int mid = (l + r) >> 1 ;
if ( Find( mid , s ) <= a[s] ) ret = mid , r = mid - 1 ;
else l = mid + 1 ;
}
return ret ;
}
int Rbinary( int l , int r , int s ) {
int ret = s ;
while ( l <= r ) {
int mid = (l + r) >> 1 ;
if ( Find( s , mid ) <= a[s] ) ret = mid , l = mid + 1 ;
else r = mid - 1 ;
}
return ret ;
}
int NewNode( int last ) {
++ Cnt ;
T[Cnt] = T[last] ;
return Cnt ;
}
void Insert( int v , int l , int r , int x , int val ) {
if ( l == r ) {
T[v].tot ++ ;
T[v].Sum1 += x ;
T[v].Sum2 += val ;
return ;
}
int mid = (l + r) >> 1 ;
if ( x <= mid ) {
T[v].Son[0] = NewNode( T[v].Son[0] ) ;
Insert( T[v].Son[0] , l , mid , x , val ) ;
} else {
T[v].Son[1] = NewNode( T[v].Son[1] ) ;
Insert( T[v].Son[1] , mid + 1 , r , x , val ) ;
}
T[v].tot = T[T[v].Son[0]].tot + T[T[v].Son[1]].tot ;
T[v].Sum1 = T[T[v].Son[0]].Sum1 + T[T[v].Son[1]].Sum1 ;
T[v].Sum2 = T[T[v].Son[0]].Sum2 + T[T[v].Son[1]].Sum2 ;
}
void Search( int lv , int rv , int l , int r , int x , int y ) {
if ( T[rv].tot == T[lv].tot ) return ;
if ( l == x && r == y ) {
ret1 += T[rv].Sum1 - T[lv].Sum1 ;
ret2 += T[rv].Sum2 - T[lv].Sum2 ;
ret3 += T[rv].tot - T[lv].tot ;
return ;
}
int mid = (l + r) >> 1 ;
if ( y <= mid ) Search( T[lv].Son[0] , T[rv].Son[0] , l , mid , x , y ) ;
else if ( x > mid ) Search( T[lv].Son[1] , T[rv].Son[1] , mid + 1 , r , x , y ) ;
else {
Search( T[lv].Son[0] , T[rv].Son[0] , l , mid , x , mid ) ;
Search( T[lv].Son[1] , T[rv].Son[1] , mid + 1 , r , mid + 1 , y ) ;
}
}
int main() {
freopen( "sf.in" , "r" , stdin ) ;
freopen( "sf.out" , "w" , stdout ) ;
n = Read() , m = Read() , p1 = Read() , p2 = Read() ;
Tab[1] = 0 ;
for (int i = 1 ; i <= n ; i ++ ) {
a[i] = Read() ;
f[i][0] = a[i] ;
if ( i > 1 ) Tab[i] = Tab[i/2] + 1 ;
}
for (int j = 1 ; j < MAXN ; j ++ ) {
for (int i = 1 ; i + (1 << (j - 1)) <= n ; i ++ ) {
f[i][j] = max( f[i][j-1] , f[i+(1<<(j-1))][j-1] ) ;
}
}
for (int i = 1 ; i <= n ; i ++ ) {
Pre[i] = Lbinary( 1 , i , i ) - 1 ;
Next[i] = Rbinary( i , n , i ) + 1 ;
}
for (int i = 1 ; i <= n ; i ++ ) {
Root[i] = NewNode( Root[i-1] ) ;
Insert( Root[i] , 0 , n + 1 , Pre[i] , i ) ;
}
for (int i = 1 ; i <= m ; i ++ ) {
Q[i].l = Read() , Q[i].r = Read() ;
int l = Q[i].l , r = Q[i].r ;
ret1 = ret2 = ret3 = 0 ;
Search( Root[Q[i].l-1] , Root[Q[i].r] , 0 , n + 1 , Q[i].l , n + 1 ) ;
tot1[i] = ret3 ;
tot2[i] = ret2 - ret1 - ret3 ;
ll S = (l + r) * (r - l + 1) / 2 ;
tot2[i] += (S - ret2) - l * ((r - l + 1) - ret3) ;
}
Cnt = 0 ;
memset( T , 0 , sizeof(T) ) ;
for (int i = 1 ; i <= n ; i ++ ) {
Root[i] = NewNode( Root[i-1] ) ;
Insert( Root[i] , 0 , n + 1 , Next[i] , i ) ;
}
for (int i = 1 ; i <= m ; i ++ ) {
int l = Q[i].l , r = Q[i].r ;
ret1 = ret2 = ret3 = 0 ;
Search( Root[Q[i].l-1] , Root[Q[i].r] , 0 , n + 1 , 0 , Q[i].r ) ;
tot1[i] += ret3 ;
tot2[i] += ret1 - ret2 - ret3 ;
ll S = (l + r) * (r - l + 1) / 2 ;
tot2[i] += r * ((r - l + 1) - ret3) - (S - ret2) ;
}
for (int i = 1 ; i <= m ; i ++ ) {
tot2[i] -= tot1[i] ;
printf( "%lld\n" , tot1[i] * p1 + tot2[i] * p2 ) ;
}
return 0 ;
}
以上.