HNOI2017 影魔

来源:互联网 发布:淘宝手机端复制链接 编辑:程序博客网 时间:2024/04/28 14:41

题解

Prei表示i前面恰好比i大的位置,Sufi表示i后面恰好比i大的位置。
对于一个询问[l,r]考虑将p1,p2的贡献分开计算。对于p1,要满足max(ki+1,...,kj1)min(ki,kj),一个位置i将其当做较小值,那么贡献就是ri=l[Preil]+[Sufir],所以可以用主席树维护。对于p2,要满足min(ki,kj)max(ki+1,...,kj1)max(ki,kj)不太好处理,考虑只求满足max(ki+1,...,kj1)max(ki,kj),然后减去p1的贡献,一个位置i将其当做较大值,那么贡献就是ri=limax(Prei+1,l)+min(Sufi1,r)也可以讨论一下拆开min,max然后主席树维护。

时间复杂度:O(nlogn)

SRC

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>#include<cmath>using namespace std ;#define N 200000 + 10const 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 ;}

以上.

1 0
原创粉丝点击