BZOJ-2821: 作诗(Poetize)(分块+二分)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2821

我这道题借鉴了一下2741的做法,先分成sqrt(n)块,对于每块的最后一个点x,预处理出每个x到后面位置的答案,然后对于一个询问[l,r],就拆成[l,x)+[x,r],[x,r]的内容已经预处理出,然后枚举[l,x)里的每一个权值,用二分查找进行统计,然后分类讨论即可。

代码:

#include <cstdio>

#include <algorithm>

#include <cstring>

#include <cmath>

 

using namespace std ;

 

#define maxn 100001

#define maxc 100001

#define maxb 320

#define inf 0x7fffffff

 

struct saver {

    int v , t ;

    bool operator < ( const saver &a ) const {

        return v < a.v || ( v == a.v && t < a.t ) ;

    }

    bool operator == ( const saver &a ) const {

        return v == a.v && t == a.t ;

    }

    bool operator > ( const saver &a ) const {

        return v > a.v || ( v == a.v && t > a.t ) ;

    }

} b[ maxn * 3 ] ;

 

saver make( int v , int t ) {

    saver u ;

    u.v = v , u.t = t ;

    return u ;

}

 

int bn = 0 ;

 

int n , m , c , a[ maxn ] , left[ maxc ] , right[ maxc ] ;

 

void Init(  ) {

    scanf( "%d%d%d" , &n , &c , &m ) ;

    for ( int i = 0 ; i ++ < n ; ) {

        scanf( "%d" , a + i ) ;

        b[ ++ bn ] = make( a[ i ] , i ) ;

    }

    for ( int i = 0 ; i ++ < c ; ) {

        b[ ++ bn ] = make( i , 0 ) ;

        b[ ++ bn ] = make( i , inf ) ;

    }

    sort( b + 1 , b + bn + 1 ) ;

    for ( int i = 0 ; i ++ < bn ; ) {

        if ( ! b[ i ].t ) left[ b[ i ].v ] = i ;

        if ( b[ i ].t == inf ) right[ b[ i ].v ] = i ;

    }

}

 

int R[ maxb ][ maxn ] , num[ maxn ] , p[ maxb ] , cnt[ maxc ] ;

int len , N ;

 

void Divide(  ) {

    len = int( sqrt( n ) ) ;

    N = 0 , p[ 0 ] = 0 ;

    memset( num , 0 , sizeof( num ) ) ;

    for ( int i = len ; i <= n ; i += len ) {

        p[ ++ N ] = i ;

        for ( int j = i ; j > p[ N - 1 ] ; -- j ) num[ j ] = N ;

    }

    for ( int i = 0 ; i ++ < N ; ) {

        for ( int j = 0 ; j ++ < c ; ) cnt[ j ] = 0 ;

        int ret = 0 ;

        for ( int j = p[ i ] ; j <= n ; ++ j ) {

            if ( cnt[ a[ j ] ] ) {

                if ( cnt[ a[ j ] ] % 2 ) ++ ret ;

                else -- ret ;

            }

            ++ cnt[ a[ j ] ] , R[ i ][ j ] = ret ;

        }

    }

}

 

int upper( saver x ) {

    int l = left[ x.v ] , r = right[ x.v ] ;

    while ( r - l > 1 ) {

        int mid = ( l + r ) >> 1 ;

        if ( b[ mid ] > x ) r = mid ; else l = mid ;

    }

    return l ;

}

 

int lower( saver x ) {

    int l = left[ x.v ] , r = right[ x.v ] ;

    while ( r - l > 1 ) {

        int mid = ( l + r ) >> 1 ;

        if ( b[ mid ] < x ) l = mid ; else r = mid ;

    }

    return l ;

}

 

int counter( int l , int r , int v ) {

    return upper( make( v , r ) ) - lower( make( v , l ) ) ;

}

 

int Index = 0 ;

 

int query( int l , int r ) {

    ++ Index ;

    if ( num[ l ] == num[ r ] ) {

        int ret = 0 ;

        for ( int i = l ; i <= r ; ++ i ) if ( cnt[ a[ i ] ] < Index ) {

            cnt[ a[ i ] ] = Index ;

            int cn = counter( l , r , a[ i ] ) ;

            if ( ! ( cn % 2 ) ) ++ ret ;

        }

        return ret ;

    } else {

        int pos = p[ num[ l ] ] ;

        int ret = R[ num[ l ] ][ r ] ;

        for ( int i = l ; i < pos ; ++ i ) if ( cnt[ a[ i ] ] < Index ) {

            cnt[ a[ i ] ] = Index ;

            int cnt0 = counter( l , pos - 1 , a[ i ] ) ;

            int cnt1 = counter( pos , r , a[ i ] ) ;

            if ( cnt1 ) {

                if ( cnt0 % 2 ) {

                    if ( cnt1 % 2 ) ++ ret ; else -- ret ;

                }

            } else if ( cnt0 && ! ( cnt0 % 2 ) ) ++ ret ;

        }

        return ret ;

    }

}

 

void Solve(  ) {

    memset( cnt , 0 , sizeof( cnt ) ) ;

    int ans = 0 ;

    while ( m -- ) {

        int x , y , l , r ; scanf( "%d%d" , &x , &y ) ;

        l = ( x + ans ) % n + 1 , r = ( y + ans ) % n + 1 ;

        if ( l > r ) swap( l , r ) ;

        printf( "%d\n" , ans = query( l , r ) ) ;

    }

}

 

int main(  ) {

    Init(  ) ;

    Divide(  ) ;

    Solve(  ) ;

    return 0 ;

}


    原文作者:AmadeusChan
    原文地址: https://www.jianshu.com/p/2980ca832afa
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞