浏览器标题切换
浏览器标题切换end
把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

BZOJ2724 [Violet]蒲公英 分块

题目描述

经典区间众数题目

然而是权限题,所以题目链接放Luogu的

题解

因为太菜所以只会$O(n*\sqrt{n}+n*\sqrt{n}*log(n))$的做法

就是那种要用二分的,并不会clj那种不带log的做法

首先数的值域为1e9肯定要离散化一下

因为数最多有40000个所以开40000个vector,存一下每个数出现的位置

预处理出每个以块的端点为左右端点的区间的众数,这种区间一共有O(block^2)个,所以可以用O(n*block)的时间复杂度来预处理

可以发现的一点是,每个区间的众数,要么是散块里面的数,要么是中间所有整块的区间众数(因为散块中出现的那些数增加了中间的整块中第二大第三大的这些区间众数的出现次数,他们就有可能篡位了)

那么我们可以在离散化之后,将每个数出现的位置存到一个vector里面,在处理散块中的数的时候,我们可以通过二分查找找出这个区间中该数出现过几次(二分查找右端点和左端点相减),效率是$O(\sqrt{n}*log(n))$

整块直接调用我们预处理出来的区间众数就可以了

#include <bits/stdc++.h>

#define ll long long
#define inf 0x3f3f3f3f
#define il inline

namespace io {

    #define in(a) a=read()
    #define out(a) write(a)
    #define outn(a) out(a),putchar('\n')

    #define I_int int
    inline ll read() {
        ll x = 0 , f = 1 ; char c = getchar() ;
        while( c < '0' || c > '9' ) { if( c == '-' ) f = -1 ; c = getchar() ; }
        while( c >= '0' && c <= '9' ) { x = x * 10 + c - '0' ; c = getchar() ; }
        return x * f ;
    }
    char F[ 200 ] ;
    inline void write( I_int x ) {
        if( x == 0 ) { putchar( '0' ) ; return ; }
        I_int tmp = x > 0 ? x : -x ;
        if( x < 0 ) putchar( '-' ) ;
        int cnt = 0 ;
        while( tmp > 0 ) {
            F[ cnt ++ ] = tmp % 10 + '0' ;
            tmp /= 10 ;
        }
        while( cnt > 0 ) putchar( F[ -- cnt ] ) ;
    }
    #undef I_int

}
using namespace io ;

using namespace std ;

#define N 100010

map< int , int > mp ;
vector< int > vt[ N ] ;
int val[ N ] , a[ N ] ;
int t[ 5010 ][ 5010 ] ;
int n , tot = 0 ;
int block , num , bl[ N ] , L[ N ] , R[ N ] ; 
int cnt[ N ] ;

void pre( int x ) {
    int mx = 0 , id = 0 ;
    memset( cnt , 0 , sizeof( cnt ) ) ;
    for( int i = L[ x ] ; i <= n ; i ++ ) {
        cnt[ a[ i ] ] ++ ;
        if( cnt[ a[ i ] ] > mx || (cnt[ a[ i ] ] == mx && val[ a[ i ] ] < val[ id ] ) ) {
            mx = cnt[ a[ i ] ] ; id = a[ i ] ;
        }
        t[ x ][ bl[ i ] ] = id ;
    }
}

void build() {
    block = 30 ;
    num = n / block ;
    if( n % block ) num ++ ;
    for( int i = 1 ; i <= num ; i ++ ) {
        L[ i ] = (i - 1) * block + 1 ;
        R[ i ] = i * block ;
    }
    R[ num ] = n ;
    for( int i = 1 ; i <= n ; i ++ ) bl[ i ] = (i - 1) / block + 1 ;
    for( int i = 1 ; i <= num ; i ++ ) pre( i ) ;
}

int serach_ans( int l , int r , int x ) {
    return upper_bound( vt[ x ].begin() , vt[ x ].end() , r ) - lower_bound( vt[ x ].begin() , vt[ x ].end() , l ) ;
}

int query( int l , int r ) {
    int mx = 0 , id = t[ bl[ l ] + 1 ][ bl[ r ] - 1 ] ;
    mx = serach_ans( l , r , id ) ;
    if( bl[ l ] == bl[ r ] ) {
        for( int i = l ; i <= r ; i ++ ) {
            int x = serach_ans( l , r , a[ i ] ) ;
            if( x > mx || (x == mx && val[ a[ i ] ] < val[ id ])) { mx = x ; id = a[ i ] ; }
        }
        return id ;
    }
    for( int i = l ; i <= R[ bl[ l ] ] ; i ++ ) {
        int x = serach_ans( l , r , a[ i ] ) ;
        if( x > mx || (x == mx && val[ a[ i ] ] < val[ id ])) { mx = x ; id = a[ i ] ; }
    }
    for( int i = L[ bl[ r ] ] ; i <= r ; i ++ ) {
        int x = serach_ans( l , r , a[ i ] ) ;
        if( x > mx || (x == mx && val[ a[ i ] ] < val[ id ])) { mx = x ; id = a[ i ] ; }
    }
    return id ;
}

int main() {
    n = read() ; int m = read() ;
    int ans = 0 ;
    for( int i = 1 ; i <= n ; i ++ ) {
        a[ i ] = read() ;
        if( mp[ a[ i ] ] == 0 ) { mp[ a[ i ] ] = ++ tot , val[ tot ] = a[ i ] ; }
        a[ i ] = mp[ a[ i ] ] ;
        vt[ a[ i ] ].push_back( i ) ;
    }
    build() ;
    for( int i = 1 ; i <= m ; i ++ ) {
        int l = read() , r = read() ;
        l = (l + ans - 1) % n + 1 , r = (r + ans - 1) % n + 1 ;
        if( l > r ) swap( l , r ) ;
        outn( ans = val[ query( l , r ) ] ) ;
     }
     return 0 ;
}

 

posted @ 2018-11-23 21:02  henry_y  阅读(158)  评论(0编辑  收藏  举报