1. 程式人生 > >BZOJ2724 [Violet]蒲公英 分塊

BZOJ2724 [Violet]蒲公英 分塊

題目描述

經典區間眾數題目

然而是許可權題,所以題目連結放Luogu的

題解

因為太菜所以只會$O(n*sqrt(n)+n*sqrt(n)*log(sqrt(n))$的做法

就是那種要用二分的,並不會clj那種不帶log的做法

首先數的值域為1e9肯定要離散化一下

因為數最多有40000個所以開40000個vector,存一下每個數出現的位置

預處理出每個以塊的端點為左右端點的區間的眾數,這種區間一共有O(block^2)個,所以可以用O(n*block)的時間複雜度來預處理

可以發現的一點是,每個區間的眾數,要麼是散塊裡面的數,要麼是中間所有整塊的區間眾數(因為散塊中出現的那些數增加了中間的整塊中第二大第三大的這些區間眾數的出現次數,他們就有可能篡位了)

那麼我們可以在離散化之後,將每個數出現的位置存到一個vector裡面,在處理散塊中的數的時候,我們可以通過二分查詢找出這個區間中該數出現過幾次(二分查詢右端點和左端點相減),效率是O(sqrt(n)*log2(sqrt(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 ; }