Official

C - Cards Query Problem Editorial by cn449


以下、この解説では \(i\) 番目の形式のクエリをクエリ \(i\) と表記します。
配列 \(box_1, box_2, \ldots, box_N\) および \(card_1, card_2, \ldots, card_{200000}\) を持っておきます。\(box_i\) では箱 \(i\) に入っているカードの多重集合、\(card_i\) では \(i\) が書かれたカードが入っている箱の番号の集合を管理します。
クエリ \(1\) では \(card_i\)\(j\) を追加し、\(box_j\)\(i\) を追加します。これは各クエリ \(\mathrm{O} (1)\) で行えます。
クエリ \(2\) では問われている対象(具体的には、\(box_i\))に対し昇順に sort をし出力、クエリ \(3\) ではそれに加えて重複要素の削除を行えばよいです。これは出力する数の個数の合計を \(S\) とするとすべてのクエリで合わせて \(\mathrm{O} (S\log S)\) で行うことができ、\(S \leq 200000\) より十分高速です。
クエリ \(1\) のたびに sort を行うと TLE になることに注意してください(例えば、1 1 1 というクエリがたくさん与えられる状況などを考えてください) 。

実装例

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int N = 200010;
const int M = 200010;
vector<vector<int>> box(N, vector<int>());
vector<vector<int>> card(M, vector<int>());

int main() {
	int n, q;
	cin >> n >> q;
	vector<vector<int>> ans;
	while (q--) {
		int t;
		cin >> t;
		if (t == 1) {
			int i, j;
			cin >> i >> j;
			card[i].push_back(j);
			box[j].push_back(i);
		}
		else if (t == 2) {
			int i;
			cin >> i;
			sort(box[i].begin(), box[i].end());
			for (int j = 0; j < box[i].size(); j++) {
				cout << box[i][j] << "\n "[j + 1 != box[i].size()];
			}
		}
		else {
			int i;
			cin >> i;
			sort(card[i].begin(), card[i].end());
			card[i].erase(unique(card[i].begin(), card[i].end()), card[i].end());
			for (int j = 0; j < card[i].size(); j++) {
				cout << card[i][j] << "\n "[j + 1 != card[i].size()];
			}
		}
	}
}

posted:
last update: