0w1

HR Nominating Group Leaders ( Mo's Algorithm, Sqrt Decomposition )

Programming Problems and Competitions :: HackerRank

題意:
N 個人排成一排,每個人對人投一個票。Q 筆詢問,問 [ L, R ] 中,是否有恰好得到 X 票的人,如果有,輸出其中編號最小的。

制約:
1 ≤ T ≤ 5
1 ≤ N, Q ≤ 1e5
N 的總和和 Q 的總和不超過 3e5。

解法:
顯然可以用莫隊,只是編號最小怎麼處理?
額外維護一個二維陣列:
cnt_freq[ i ][ j ]:編號在 [ i * BS, ( i + 1 ) * BS ) 中的人裡,當前有 j 票的人數。
有了這個,在 N^0.5 的時間內找到答案是在哪一個塊裡,接著再花費 N^0.5 的時間線性搜尋塊裡的元素。

時間 / 空間複雜度:
O( ( N + Q ) ^ 1.5 )

#include <bits/stdc++.h>
using namespace std;

const int MAXN = int( 1e5 );
const int MAXQ = int( 1e5 );
const int BS = 350;

int N;
int V[ MAXN ];
int Q;
int L[ MAXQ ], R[ MAXQ ], X[ MAXQ ];
int qord[ MAXQ ];

int freq[ MAXN ];
int cnt_freq[ BS ][ MAXN + 1 ];

int ans[ MAXQ ];

signed main() {
  ios::sync_with_stdio( 0 );
  int T;
  cin >> T;
  for( int ti = 0; ti < T; ++ti ) {
    cin >> N;
    for( int i = 0; i < N; ++i ) {
      cin >> V[ i ];
    }
    cin >> Q;
    for( int i = 0; i < Q; ++i ) {
      cin >> L[ i ] >> R[ i ] >> X[ i ];
      qord[ i ] = i;
    }
    sort( qord, qord + Q, [ & ]( int i, int j ) {
            if( L[ i ] / BS != L[ j ] / BS ) return L[ i ] / BS < L[ j ] / BS;
            return R[ i ] < R[ j ]; } );
    memset( freq, 0, sizeof( freq ) );
    memset( cnt_freq, 0, sizeof( cnt_freq ) );
    memset( ans, -1, sizeof( ans ) );
    for( int qi = 0, lb = 1, rb = 0; qi < Q; ++qi ) {
      int ql = L[ qord[ qi ] ];
      int qr = R[ qord[ qi ] ];
      int qx = X[ qord[ qi ] ];
      while( ql < lb ) {
        --lb;
        --cnt_freq[ V[ lb ] / BS ][ freq[ V[ lb ] ] ];
        ++freq[ V[ lb ] ];
        ++cnt_freq[ V[ lb ] / BS ][ freq[ V[ lb ] ] ];
      }
      while( lb < ql ) {
        --cnt_freq[ V[ lb ] / BS ][ freq[ V[ lb ] ] ];
        --freq[ V[ lb ] ];
        ++cnt_freq[ V[ lb ] / BS ][ freq[ V[ lb ] ] ];
        ++lb;
      }
      while( rb < qr ) {
        ++rb;
        --cnt_freq[ V[ rb ] / BS ][ freq[ V[ rb ] ] ];
        ++freq[ V[ rb ] ];
        ++cnt_freq[ V[ rb ] / BS ][ freq[ V[ rb ] ] ];
      }
      while( qr < rb ) {
        --cnt_freq[ V[ rb ] / BS ][ freq[ V[ rb ] ] ];
        --freq[ V[ rb ] ];
        ++cnt_freq[ V[ rb ] / BS ][ freq[ V[ rb ] ] ];
        --rb;
      }
      for( int bi = 0; bi <= ( N - 1 ) / BS; ++bi ) {
        if( cnt_freq[ bi ][ qx ] ) {
          for( int i = bi * BS; i < ( bi + 1 ) * BS; ++i ) {
            if( freq[ i ] == qx ) {
              ans[ qord[ qi ] ] = i;
              break;
            }
          }
          break;
        }
      }
    }
    for( int i = 0; i < Q; ++i ) {
      cout << ans[ i ] << "\n";
    }
  }
  return 0;
}