配点: 350 点 / 実行時間制限: 2 sec / メモリ制限: 1024 MB / Difficulty: 919
問題概要
それぞれ の番号が付いた
羽の鳩と巣があり、はじめ、鳩
は巣
にいる。
これらの鳩に対して、以下の3種類の形式のクエリを順に 個処理せよ。
1 a b
: 整数に対して、鳩
を今いる巣から取り出し、巣
へ移動する。
2 a b
: 整数に対して、巣
にいる鳩をすべて巣
へ移動し、巣
にいる鳩をすべて巣
へ移動する。これら2つの移動は一斉に行われる。
3 a
: 整数に対して、鳩
が今いる巣の番号を出力する。
制約
- 入力はすべて整数。
考察
クエリ処理の問題は、各クエリごとに必要な情報を書きだしていくとよい。なお、説明の都合上、クエリ1 → 3 → 2 の順に書いていく。
クエリ1
鳩 が今いる巣の番号が分かれば、それを
に書き換えるだけ。したがって、
鳩
が今いる巣の番号
という配列を用意する。
クエリ3
これも先ほどの という配列があれば、すぐに答えを出すことができる。
クエリ2
素直にやろうとすると
であるものを全て
に書き換え、
であるものを全て
に書き換える
となるが、 だけでこのような
を探してくるためには、それぞれ
かかってしまう。
当然これでは TLE してしまうので、ここの処理を高速化したい。
ここで1つ思うのは、「鳩がいる巣を変えるのではなくて、巣の番号だけ変えてしまえばいいのでは?」ということ。
巣自体にも番号が書かれているので、巣に貼り紙(ラベル)を貼っておくことにして、そのラベルを貼り替えることを考える。

ということで、次の2つの配列を用意する。
巣
に貼ってあるラベルの番号
ラベル
が貼ってある巣の番号
「巣 → ラベル」と「ラベル → 巣」の関係をどちらも保持しておくことによって、クエリ1とクエリ3の両方に対応することができる。
各クエリの処理は以下の通り。なお、初期状態では である。
- クエリ1 :
とする。
- クエリ2 :
と
を
swap
する。その後、とする。
- クエリ3 :
を出力する。
実装例
#include <bits/stdc++.h> using namespace std; #define all(x) (x).begin(), (x).end() // ======================================== // int main() { int N, Q; cin >> N >> Q; vector<int> pigeons(N + 1), houses(N + 1), labels(N + 1); iota(all(pigeons), 0); iota(all(houses), 0); iota(all(labels), 0); while (Q--) { int op; cin >> op; if (op == 1) { int a, b; cin >> a >> b; pigeons[a] = labels[b]; } else if (op == 2) { int a, b; cin >> a >> b; swap(labels[a], labels[b]); houses[labels[a]] = a; houses[labels[b]] = b; } else if (op == 3) { int a; cin >> a; cout << houses[pigeons[a]] << endl; } } return 0; }
実装時間: 30分
コメント
C問題に続いて「配列のインデックスを別の配列に記録する」が有効だった。巣とは別にラベルの存在を考えるのが結構難しいかも?