最新!邦克仕推出蘋果 iPhone 12/mini/Pro/Pro Max 貼膜保護殼:「iPhone 4」邊框設計迴歸
阿新 • • 發佈:2020-10-11
題意簡述
區間眾數出現次數強制線上。
題解
三個 YLST 中比較清新的一個分塊。
要維護的東西就只有一個 app[i]
,表示第 \(i\) 塊的眾數出現次數。
那麼我們就可以 \(\Theta(n)\) 的預處理出來了。
不過這樣會莫名 RE,於是跟題解一通對拍後我放棄人生把狀態換成了 App[i][j]
表示塊 \(i\) 到塊 \(j\) 的眾數出現次數。
不過我把一維狀態的程式碼留著,有神仙知道問題在哪裡的話請到 這個帖子 回覆我,感謝。
比較重點的地方在於詢問散塊的處理。
先離散化一下序列。
我們首先預處理出來一個 vector 陣列 fur[i]
,fur[i]
裡面依次存的是所有 isa[i]
pos[i]
表示在當前第 \(i\) 位時 fur[i]
的大小也就是一共出現了多少個 isa[i]
。由於 vector 的下標是從 \(0\) 開始的,所以所有的 pos[i]
都需要減個一。
然後詢問處理整塊的時候,我們先假設當前詢問的區間是 [opl,opr]
,然後把當前詢問的答案 res
先置為 App[bel[opl] + 1][bel[opr] - 1]
。
然後來考慮散塊,在處理出的 vector 陣列中判斷即可。
設散塊處理到數 isa[i]
,那麼如果存在 pos[i] + res <= fur[isa[i]].size() - 1
fur[isa[i]][pos[i] + res] <= opr
,那麼則說明這個數出現了至少 res + 1
次,將 res
加一即可。
由於 res
最多加不超過 \(\Theta(2\sqrt{n})\) 次,所以複雜度是對的。
#include <cstdio> #include <algorithm> #include <cstring> #include <queue> using namespace std; const int MAXN = 5e5 + 5, MAXM = 720 + 5; char buf[1 << 21], *p1 = buf, *p2 = buf; #define getchar( ) ( p1 == p2 && ( p2 = ( p1 = buf ) + fread( buf, 1, 1 << 21, stdin ), p1 == p2 ) ? EOF : *p1 ++ ) template<typename _T> void read( _T &x ){ x = 0; char c = getchar( ); _T f = 1; while( c < '0' || c > '9' ){ if( c == '-' ) f = -1; c = getchar( ); } while( c >= '0' && c <= '9' ){ x = ( x << 3 ) + ( x << 1 ) + ( c & 15 ); c = getchar( ); } x *= f; } template<typename _T> void write( _T x ){ if( x < 0 ){ putchar( '-' ); x = -x; } if( x > 9 ){ write( x / 10 ); } putchar( x % 10 + '0' ); } template<typename _T> void swapp( _T &one, _T &another ){ int temp = one; one = another; another = temp; } template<typename _T> _T MIN( _T one, _T another ){ return one > another ? another : one; } template<typename _T> _T MAX( _T one, _T another ){ return one > another ? one : another; } int N, M; int cube, each, kase, isa[MAXN], cnt[MAXN], pos[MAXN], vis[MAXN], bel[MAXN]; int lps[MAXM], rps[MAXM], app[MAXM], App[MAXM][MAXM]; vector<int> disc, fur[MAXN]; int getID( int x ){ return lower_bound( disc.begin( ), disc.end( ), x ) - disc.begin( ) + 1; } void build( ){ for( int i = 1; i <= cube; ++ i ){ kase ++; for( int j = lps[i]; j <= rps[i]; ++ j ){ if( vis[isa[j]] != kase ) cnt[isa[j]] = 0; cnt[isa[j]] ++; app[i] = MAX( app[i], cnt[isa[j]] ); vis[isa[j]] = kase; } } memset( cnt, 0, sizeof( cnt ) ); for( int i = 1; i <= cube; ++ i ){ kase ++; for( int j = i; j <= cube; ++ j ){ App[i][j] = App[i][j - 1]; for( int k = lps[j]; k <= rps[j]; ++ k ){ if( vis[isa[k]] != kase ) cnt[isa[k]] = 0; cnt[isa[k]] ++; App[i][j] = MAX( App[i][j], cnt[isa[k]] ); vis[isa[k]] = kase; } } } memset( cnt, 0, sizeof( cnt ) ); } int query( int opl, int opr ){ if( bel[opl] == bel[opr] ){ int res = 0; kase ++; for( int i = opl; i <= opr; ++ i ){ if( vis[isa[i]] != kase ) cnt[isa[i]] = 0; cnt[isa[i]] ++; res = MAX( res, cnt[isa[i]] ); vis[isa[i]] = kase; } return res; } int res = 0; // res = App[bel[opl] + 1][bel[opr] - 1]; for( int i = bel[opl] + 1; i < bel[opr]; ++ i ) res += app[i]; // for( int i = bel[opl] + 1; i < bel[opr]; ++ i ) res += App[i][i]; for( int i = opl; i <= rps[bel[opl]]; ++ i ){ int lim = fur[isa[i]].size( ) - 1; while( pos[i] + res <= lim && fur[isa[i]][pos[i] + res] <= opr ) res ++; } for( int i = lps[bel[opr]]; i <= opr; ++ i ){ while( pos[i] - res >= 0 && fur[isa[i]][pos[i] - res] >= opl ) res ++; } return res; } signed main( ){ read( N ); read( M ); each = 720; cube = ( N - 1 ) / each + 1; for( int i = 1; i <= N; ++ i ){ read( isa[i] ); disc.push_back( isa[i] ); } sort( disc.begin( ), disc.end( ) ); disc.erase( unique( disc.begin( ), disc.end( ) ), disc.end( ) ); for( int i = 1; i <= N; ++ i ){ isa[i] = getID( isa[i] ); fur[isa[i]].push_back( i ); pos[i] = fur[isa[i]].size( ) - 1; } for( int i = 1; i <= cube; ++ i ){ lps[i] = rps[i - 1] + 1; rps[i] = rps[i - 1] + each; if( i == cube ) rps[i] = N; for( int j = lps[i]; j <= rps[i]; ++ j ) bel[j] = i; } build( ); int Ans = 0, opl, opr; while( M -- > 0 ){ read( opl ); read( opr ); opl ^= Ans; opr ^= Ans; Ans = 0; if( opl > opr ) swapp( opl, opr ); write( Ans = query( opl, opr ) ); putchar( '\n' ); } return 0; }