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

#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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值