競技プログラミング日記

主に AtCoder の記事です

第三回 アルゴリズム実技検定 L問題

 

PAST003L

データ構造を用いたシュミレーションの高速化問題.

\(1 \leq a_{i} \leq 2\) と小さいので,そこから考える. 簡単のため, まずは\(a_{i} = 1\) で考える.

最大値を高速に求める必要がある. 消費期限はすべて異なるので,set型で実現できる. 最大を削除するのは,\(O(log N)\) でできる. ただし,削除だけでなく補充もしないといけないので, どの列から削除したのか,index も取得したい.
方法として考えられるのは,

  • (value, index) のペアで管理する,
  • map : value \(\mapsto\) index を用意する.

今回は後者で実装する.
補充する候補をqueue で管理しておく.
\(q_{i} := i 列目に補充する候補\)
とする.

\(a_{i} = 2\)の場合も同様.
\(s_{j} := 前からj番目の商品の消費期限全体の集合\)
とする. あとは購入と補充を実装すればよい.

使っている記号,マクロ等 "https://ecsmtlir.hatenablog.com/entry/2022/12/23/131925"

int main() {
  ll n;
  cin >> n;
  vector<set<ll>> st(2);
  vvll v(2, vll(n)); // rem : v[0][j] は使わない
  vector<queue<ll>> q(n);

  map<ll,int> mp;
  rep(i,n){
    ll k ; cin >> k;
    rep(j,k){
      ll t; cin>> t;
      q[i].push(t);
      mp[t] = i;
    }
    q[i].push(-INFL);
    q[i].push(-INFL);
  }

  ll m; cin >> m;
  vll a(m); rep(i,m) cin >> a[i];

  rep(i,2){
    rep(j,n){
      st[i].insert(q[j].front());
      v[i][j] = q[j].front();
      q[j].pop();
    }
  }

  auto update1 = [&](ll x, ll ind) -> ll {
    st[1].erase(x);
    st[1].insert(q[ind].front());
    v[1][ind] = q[ind].front();
    q[ind].pop();

    return x;
  };
 

  auto update0 = [&](void) -> ll {
    auto it = st[0].end(); it--;
    ll ma = *it;
    int ind = mp[ma];

    ll x = v[1][ind];
    st[0].erase(ma);
    st[0].insert(x);

    update1(x, ind);

    return ma;
  };
 

  rep(i,m){
    if(a[i] == 1){
      cout << update0() << endl;
    }else{
      auto it0 = st[0].end(); it0--;
      auto it1 = st[1].end(); it1--;
     
      ll ma = max(*it0, *it1);
      int ind = mp[ma];


      if(*it0 > *it1) update0();
      else update1(ma, ind);

      cout << ma << endl;

    }
  }

  return 0;
}