0w1

POI 21 Stage 1 Couriers ( Persistent Segment Tree )

http://main.edu.pl/en/archive/oi/21/kur

題意:
給一個長度 N 的數列,接著 M 筆詢問 [ L, R ] 中是否有個數字是絕對多數,有的話輸出該數字。

資料規模:
N, M ≤ 5e5
1 ≤ P ≤ N
TL: 12000 ms
ML: 128 MB

解法:
一個持久化裸題,但記憶體卡得比較緊,要用離散化線段樹避免開展過多不必要的節點。
另外這題有基於拆散位元的思想的二分解法。

時間 / 空間複雜度:
O( N lg N + M lg N ) / O( N lg^2 N )

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

const int MAXN = ( int ) 5e5;

int N, M;

struct pst{
  static pst mem_pool[ ( int ) 1.05e7 ];
  int cnt;
  pst *lc, *rc;
  pst(){
    cnt = 0;
    lc = rc = NULL;
  }
  void pull(){
    cnt = ( lc ? lc->cnt : 0 ) + ( rc ? rc->cnt : 0 );
  }
} *root[ MAXN + 1 ], pst::mem_pool[ ( int ) 1.05e7 ], *mem_ptr = pst::mem_pool;

pst* clone( pst *t ){
  pst *res = new ( mem_ptr++ ) pst();
  res->lc = t->lc;
  res->rc = t->rc;
  res->cnt = t->cnt;
  return res;
}

pst* update( pst *t, int lb, int rb, int k, int v ){
  pst *res;
  if( t ) res = clone( t );
  else res = new ( mem_ptr++ ) pst();
  if( lb + 1 == rb ){
    res->cnt += v;
    return res;
  }
  int mid = lb + rb >> 1;
  if( k < mid ) res->lc = update( res->lc, lb, mid, k, v );
  else res->rc = update( res->rc, mid, rb, k, v );
  res->pull();
  return res;
}

int dfs( pst *tl, pst *tr, int lb, int rb, int v ){
  if( lb + 1 == rb ){
    return lb;
  }
  int mid = lb + rb >> 1;
  int rl = tr ? tr->lc ? tr->lc->cnt : 0 : 0;
  int ll = tl ? tl->lc ? tl->lc->cnt : 0 : 0;
  int rr = tr ? tr->rc ? tr->rc->cnt : 0 : 0;
  int lr = tl ? tl->rc ? tl->rc->cnt : 0 : 0;
  if( rl - ll << 1 > v ){
    return dfs( ( tl ? tl->lc : NULL ), ( tr ? tr->lc : NULL ), lb, mid, v );
  }
  if( rr - lr << 1 > v ){
    return dfs( ( tl ? tl->rc : NULL ), ( tr ? tr->rc : NULL ), mid, rb, v );
  }
  return -1;
}

signed main(){
  ios::sync_with_stdio( 0 );
  cin >> N >> M;
  for( int i = 0; i < N; ++i ){
    int P; cin >> P; --P;
    root[ i + 1 ] = update( root[ i ], 0, N, P, 1 );
  }
  for( int i = 0; i < M; ++i ){
    int ql, qr; cin >> ql >> qr; --ql; // [ ql, qr )
    cout << dfs( root[ ql ], root[ qr ], 0, N, qr - ql ) + 1 << "\n";
  }
  return 0;
}