Codeforces 219(#135 Div2 only) E. Parking Lot
問題
横一列にn台の駐車スペースがあり、左から順に1, ..., nと名前がついている。
ここにm個の車の到着または出発のクエリが来るので処理せよ。
車は以下のアルゴリズムで駐車場所を選ぶ。
全ての空きスペースの中で、一番近くにある他の車までの距離が最大になる場所を選ぶ。
複数ある場合、その中で最も番号が小さい場所を選ぶ。
駐車場が空のときは1番の場所を選ぶ。
制約条件
n, m≦2*10^5
車のid番号は10^6以下の数
車が止まれない状態で駐車のクエリが来ることはない
止まっていない車の発車のクエリが来ることはない
方針
区間を平衡二分木で管理する。
区間(a, b)があるとき、ここに車が止まるなら、(a + b) / 2の位置に止まる。
平衡二分木を二つもち、
一つは(次に車が止まったときの最寄の車の位置, 区間の左端)
もう一つは(区間の左端, 区間の右端)をそれぞれ管理する。
次に車止まる位置を探したいときは、前者の平衡二分木の最初の要素をとればよいが、両端にある駐車スペースだけは例外なので、個別に処理する。
車が発車したときは、区間(x, x + 1)を追加するのだが、このとき隣接する区間とマージする処理を書く。
ソースコード
もうちょいマシな実装できないものか…
int n, q, pos[10000010]; struct S{ set<pi> iv, len; inline int find(){ #if 0 each(i, iv) cerr<<i->first<<", "<<i->second<<" "; cerr<<endl; each(i, len) cerr<<i->first<<", "<<i->second<<" "; cerr<<endl; #endif pi mx(1, 0); if(iv.begin()->first == 0){ mx = min(mx, mp(iv.begin()->first - iv.begin()->second + 1, 0)); } set<pi>::iterator it = iv.end(); --it; if(it->second == n) mx = min(mx, mp(it->first - it->second + 1, n - 1)); int b = -len.begin()->first, a = len.begin()->second; mx = min(mx, mp(-b, a + b)); return mx.second; } inline void del(int a, int b){ iv.erase(mp(a, b)); len.erase(mp(-(b - a - 1) / 2, a)); } inline void del(int x){ set<pi>::iterator it = iv.lower_bound(mp(x + 1, 0)); --it; int a = it->first, b = it->second; del(a, b); if(a < x) ins(a, x); if(x + 1 < b) ins(x + 1, b); } inline void ins(int a, int b){ iv.insert(mp(a, b)); len.insert(mp(-(b - a - 1) / 2, a)); fix(a, b); } inline void fix(int a, int b){ set<pi>::iterator it = iv.lower_bound(mp(a, b)); if(it != iv.end() && ++it != iv.end() && it->first == b){ int c = it->second; del(a, b); del(b, c); ins(a, c); } else{ it = iv.lower_bound(mp(a, b)); if(it != iv.begin() && (--it)->second == a){ int c = it->first; del(c, a); del(a, b); ins(c, b); } } } }; int main(){ scanf("%d%d", &n, &q); S s; s.ins(0, n); while(q--){ int t, id; scanf("%d%d", &t, &id); if(t == 1){ pos[id] = s.find(); printf("%d\n", pos[id] + 1); s.del(pos[id]); } else{ s.ins(pos[id], pos[id] + 1); } } return 0; }